Skip to content

Commit 98dbbe4

Browse files
Merge pull request #149 from michaelryanmcneill/ROSA-786
ROSAENG-57757 | feat: add trust_policy_external_id to account-iam-resources
2 parents 6986840 + fa134cb commit 98dbbe4

5 files changed

Lines changed: 325 additions & 21 deletions

File tree

modules/account-iam-resources/README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@ module "account_iam_resources" {
5656
| [null_resource.validate_openshift_version](https://registry.terraform.io/providers/hashicorp/null/latest/docs/resources/resource) | resource |
5757
| [random_string.default_random](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/string) | resource |
5858
| [time_sleep.account_iam_resources_wait](https://registry.terraform.io/providers/hashicorp/time/latest/docs/resources/sleep) | resource |
59-
| [aws_iam_policy_document.custom_trust_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
6059
| [aws_partition.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/partition) | data source |
6160
| [rhcs_info.current](https://registry.terraform.io/providers/terraform-redhat/rhcs/latest/docs/data-sources/info) | data source |
6261
| [rhcs_policies.all_policies](https://registry.terraform.io/providers/terraform-redhat/rhcs/latest/docs/data-sources/policies) | data source |
@@ -71,6 +70,7 @@ module "account_iam_resources" {
7170
| <a name="input_path"></a> [path](#input\_path) | The ARN path for the account/operator roles as well as their policies. | `string` | `"/"` | no |
7271
| <a name="input_permissions_boundary"></a> [permissions\_boundary](#input\_permissions\_boundary) | The ARN of the policy that is used to set the permissions boundary for the IAM roles in STS clusters. | `string` | `""` | no |
7372
| <a name="input_tags"></a> [tags](#input\_tags) | List of AWS resource tags to apply. | `map(string)` | `null` | no |
73+
| <a name="input_trust_policy_external_id"></a> [trust\_policy\_external\_id](#input\_trust\_policy\_external\_id) | External ID for trust policy condition in installer and support account roles. | `string` | `null` | no |
7474

7575
## Outputs
7676

@@ -80,4 +80,5 @@ module "account_iam_resources" {
8080
| <a name="output_account_roles_arn"></a> [account\_roles\_arn](#output\_account\_roles\_arn) | A map of Amazon Resource Names (ARNs) associated with the AWS IAM roles created. The key in the map represents the name of an AWS IAM role, while the corresponding value represents the associated Amazon Resource Name (ARN) of that role. |
8181
| <a name="output_openshift_version"></a> [openshift\_version](#output\_openshift\_version) | The Openshift cluster version of the cluster those account roles are used for. |
8282
| <a name="output_path"></a> [path](#output\_path) | The arn path for the account/operator roles as well as their policies. |
83+
| <a name="output_trust_policy_external_id"></a> [trust\_policy\_external\_id](#output\_trust\_policy\_external\_id) | External ID for trust policy condition in account roles |
8384
<!-- END_AUTOMATED_TF_DOCS_BLOCK -->

modules/account-iam-resources/main.tf

Lines changed: 45 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,17 @@
44
locals {
55
path = coalesce(var.path, "/")
66
short_openshift_version = format("%s.%s", split(".", var.openshift_version)[0], split(".", var.openshift_version)[1])
7+
trust_policy_external_id = (
8+
var.trust_policy_external_id != null && var.trust_policy_external_id != ""
9+
) ? var.trust_policy_external_id : null
710
account_roles_properties = [
811
{
912
role_name = "Installer"
1013
role_type = "installer"
1114
policy_details = data.rhcs_policies.all_policies.account_role_policies["sts_installer_permission_policy"]
1215
principal_type = "AWS"
1316
principal_identifier = "arn:${data.aws_partition.current.partition}:iam::${data.rhcs_info.current.ocm_aws_account_id}:role/RH-Managed-OpenShift-Installer"
17+
external_id = local.trust_policy_external_id
1418
},
1519
{
1620
role_name = "Support"
@@ -19,24 +23,31 @@ locals {
1923
principal_type = "AWS"
2024
// This is a SRE RH Support role which is used to assume this support role
2125
principal_identifier = data.rhcs_policies.all_policies.account_role_policies["sts_support_rh_sre_role"]
26+
external_id = local.trust_policy_external_id
2227
},
2328
{
2429
role_name = "Worker"
2530
role_type = "instance_worker"
2631
policy_details = data.rhcs_policies.all_policies.account_role_policies["sts_instance_worker_permission_policy"]
2732
principal_type = "Service"
2833
principal_identifier = "ec2.amazonaws.com"
34+
external_id = null
2935
},
3036
{
3137
role_name = "ControlPlane"
3238
role_type = "instance_controlplane"
3339
policy_details = data.rhcs_policies.all_policies.account_role_policies["sts_instance_controlplane_permission_policy"]
3440
principal_type = "Service"
3541
principal_identifier = "ec2.amazonaws.com"
42+
external_id = null
3643
}
3744
]
3845
account_roles_count = null_resource.validate_openshift_version != null ? length(local.account_roles_properties) : 0
39-
patch_version_list = [for s in data.rhcs_versions.all_versions.items : s.name]
46+
# terraform test cannot mock ListNested attributes (items) reliably; fall back to singular item.
47+
patch_version_list = distinct(concat(
48+
try([for s in data.rhcs_versions.all_versions.items : s.name], []),
49+
try([data.rhcs_versions.all_versions.item.name], []),
50+
))
4051
minor_version_list = length(local.patch_version_list) > 0 ? (
4152
distinct([for s in local.patch_version_list : format("%s.%s", split(".", s)[0], split(".", s)[1])])
4253
) : (
@@ -47,19 +58,32 @@ locals {
4758
) : (
4859
"account-role-${random_string.default_random[0].result}"
4960
)
50-
}
51-
52-
data "aws_iam_policy_document" "custom_trust_policy" {
53-
count = local.account_roles_count
54-
55-
statement {
56-
effect = "Allow"
57-
actions = ["sts:AssumeRole"]
58-
principals {
59-
type = local.account_roles_properties[count.index].principal_type
60-
identifiers = [local.account_roles_properties[count.index].principal_identifier]
61-
}
62-
}
61+
# Hand-rolled jsonencode instead of aws_iam_policy_document for terraform test compatibility.
62+
custom_trust_policy_json = [
63+
for idx in range(local.account_roles_count) : jsonencode({
64+
Version = "2012-10-17"
65+
Statement = [
66+
merge(
67+
{
68+
Effect = "Allow"
69+
Action = "sts:AssumeRole"
70+
Principal = local.account_roles_properties[idx].principal_type == "AWS" ? {
71+
AWS = local.account_roles_properties[idx].principal_identifier
72+
} : {
73+
Service = local.account_roles_properties[idx].principal_identifier
74+
}
75+
},
76+
local.account_roles_properties[idx].external_id != null ? {
77+
Condition = {
78+
StringEquals = {
79+
"sts:ExternalId" = local.account_roles_properties[idx].external_id
80+
}
81+
}
82+
} : {}
83+
)
84+
]
85+
})
86+
]
6387
}
6488

6589
module "account_iam_role" {
@@ -77,7 +101,7 @@ module "account_iam_role" {
77101
role_permissions_boundary_arn = var.permissions_boundary
78102

79103
create_custom_role_trust_policy = true
80-
custom_role_trust_policy = data.aws_iam_policy_document.custom_trust_policy[count.index].json
104+
custom_role_trust_policy = local.custom_trust_policy_json[count.index]
81105

82106
tags = merge(var.tags, {
83107
red-hat-managed = true
@@ -140,11 +164,12 @@ resource "time_sleep" "account_iam_resources_wait" {
140164
destroy_duration = "10s"
141165
create_duration = "10s"
142166
triggers = {
143-
account_iam_role_name = jsonencode([for value in aws_iam_role_policy_attachment.role_policy_attachment : value.role])
144-
account_roles_arn = jsonencode({ for idx, value in module.account_iam_role : local.account_roles_properties[idx].role_name => value.iam_role_arn })
145-
account_role_prefix = local.account_role_prefix_valid
146-
openshift_version = var.openshift_version
147-
path = var.path
167+
account_iam_role_name = jsonencode([for value in aws_iam_role_policy_attachment.role_policy_attachment : value.role])
168+
account_roles_arn = jsonencode({ for idx, value in module.account_iam_role : local.account_roles_properties[idx].role_name => value.iam_role_arn })
169+
account_role_prefix = local.account_role_prefix_valid
170+
openshift_version = var.openshift_version
171+
path = var.path
172+
trust_policy_external_id = local.trust_policy_external_id != null ? local.trust_policy_external_id : ""
148173
}
149174
}
150175

modules/account-iam-resources/outputs.tf

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,12 @@ output "path" {
2020
value = time_sleep.account_iam_resources_wait.triggers["path"]
2121
description = "The arn path for the account/operator roles as well as their policies."
2222
}
23+
24+
output "trust_policy_external_id" {
25+
value = (
26+
time_sleep.account_iam_resources_wait.triggers["trust_policy_external_id"] != ""
27+
? time_sleep.account_iam_resources_wait.triggers["trust_policy_external_id"]
28+
: null
29+
)
30+
description = "External ID for trust policy condition in account roles"
31+
}

0 commit comments

Comments
 (0)