qontract-reconcile 0.10.1rc675__py3-none-any.whl → 0.10.1rc677__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: qontract-reconcile
3
- Version: 0.10.1rc675
3
+ Version: 0.10.1rc677
4
4
  Summary: Collection of tools to reconcile services with their desired state as defined in the app-interface DB.
5
5
  Home-page: https://github.com/app-sre/qontract-reconcile
6
6
  Author: Red Hat App-SRE Team
@@ -141,7 +141,7 @@ reconcile/aws_cloudwatch_log_retention/integration.py,sha256=0UcSZIrGvnGY4m9fj87
141
141
  reconcile/aws_saml_idp/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
142
142
  reconcile/aws_saml_idp/integration.py,sha256=uqec-EnxnfGOgQtg33S-Q1wTCv0sVBHNo02aT94hXrw,4807
143
143
  reconcile/aws_saml_roles/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
144
- reconcile/aws_saml_roles/integration.py,sha256=kgAUaCfKA2ujvIym8sPSWoBf1EnRKi2vVbgKyi8eELU,5695
144
+ reconcile/aws_saml_roles/integration.py,sha256=kC4Rnbuy07TMvZO4rjUEcQkJev10M0Ro6r7YXcB7j_c,9530
145
145
  reconcile/aws_version_sync/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
146
146
  reconcile/aws_version_sync/integration.py,sha256=0rgFLL2usTnngjIgFXIEfVXapFsDI1A493Mftqjfbk0,17292
147
147
  reconcile/aws_version_sync/utils.py,sha256=sVv-48PKi2VITlqqvmpbjnFDOPeGqfKzgkpIszlmjL0,1708
@@ -190,7 +190,7 @@ reconcile/gql_definitions/aws_saml_idp/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JC
190
190
  reconcile/gql_definitions/aws_saml_idp/aws_accounts.py,sha256=ZhsTyUmR-i-0eDXEEl2qZV64bIHMK25KrvlkqpzwO8Y,2652
191
191
  reconcile/gql_definitions/aws_saml_roles/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
192
192
  reconcile/gql_definitions/aws_saml_roles/aws_accounts.py,sha256=a6tHAPKyJ4cPOYKlDPcdnLyE6i0w6jewvlrNJ3be2yk,2702
193
- reconcile/gql_definitions/aws_saml_roles/aws_groups.py,sha256=IyVzp5d8bie1dD2XLLbdpI9d1hhz6aLkPZ-FjqSf2r0,2639
193
+ reconcile/gql_definitions/aws_saml_roles/roles.py,sha256=2Bbk71rFZkB6x0TF5xe1B758jq9wUQ4JNe5-ym_u1so,2529
194
194
  reconcile/gql_definitions/aws_version_sync/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
195
195
  reconcile/gql_definitions/aws_version_sync/clusters.py,sha256=2TOJOFxpTkZ2HKuqAGUo6tQkzOINSfO-bYDINVpJeL0,2295
196
196
  reconcile/gql_definitions/aws_version_sync/namespaces.py,sha256=eBLyXlSjWdmEE-jY9M2Ocgk7JGi2OsWisTkjHLfgU_A,4311
@@ -616,7 +616,7 @@ reconcile/utils/state.py,sha256=zjsprjbOb0WddzmAvh8ACqAt0fcayrX2YPfz7qceRWw,1609
616
616
  reconcile/utils/structs.py,sha256=LcbLEg8WxfRqM6nW7NhcWN0YeqF7SQzxOgntmLs1SgY,352
617
617
  reconcile/utils/template.py,sha256=wTvRU4AnAV_o042tD4Mwls2dwWMuk7MKnde3MaCjaYg,331
618
618
  reconcile/utils/terraform_client.py,sha256=7L55Rvxfzj3KtJH8AD8D8YRfBnFpHiTFqSa5e2_9jtk,32092
619
- reconcile/utils/terrascript_aws_client.py,sha256=Jxh6boKnGAKEM-3K1AFlhF6YneOQPVoBj3q98dITNFc,271891
619
+ reconcile/utils/terrascript_aws_client.py,sha256=0kYizE48gVlcXxGdtKcdrbw5Xkb2uQ0ao1stov4lyhU,272099
620
620
  reconcile/utils/three_way_diff_strategy.py,sha256=nyqeQsLCoPI6e16k2CF3b9KNgQLU-rPf5RtfdUfVMwE,4468
621
621
  reconcile/utils/throughput.py,sha256=iP4UWAe2LVhDo69mPPmgo9nQ7RxHD6_GS8MZe-aSiuM,344
622
622
  reconcile/utils/unleash.py,sha256=1D56CsZfE3ShDtN3IErE1T2eeIwNmxhK-yYbCotJ99E,3601
@@ -723,8 +723,8 @@ tools/test/test_app_interface_metrics_exporter.py,sha256=SX7qL3D1SIRKFo95FoQztvf
723
723
  tools/test/test_qontract_cli.py,sha256=OvalpVRfY4pNmpMaWHHYqBjV68b1eGQjX8SCyTAXb1w,3501
724
724
  tools/test/test_sd_app_sre_alert_report.py,sha256=v363r9zM7__0kR5K6mvJoGFcM9BvE33fWAayrqkpojA,2116
725
725
  tools/test/test_sre_checkpoints.py,sha256=SKqPPTl9ua0RFdSSofnoQX-JZE6dFLO3LRhfQzqtfh8,2607
726
- qontract_reconcile-0.10.1rc675.dist-info/METADATA,sha256=otHpW3N3ydPZOwDWRdiqZjFC2DmYoGee9x0GfVeIzFU,2382
727
- qontract_reconcile-0.10.1rc675.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
728
- qontract_reconcile-0.10.1rc675.dist-info/entry_points.txt,sha256=rIxI5zWtHNlfpDeq1a7pZXAPoqf7HG32KMTN3MeWK_8,429
729
- qontract_reconcile-0.10.1rc675.dist-info/top_level.txt,sha256=l5ISPoXzt0SdR4jVdkfa7RPSKNc8zAHYWAnR-Dw8Ey8,24
730
- qontract_reconcile-0.10.1rc675.dist-info/RECORD,,
726
+ qontract_reconcile-0.10.1rc677.dist-info/METADATA,sha256=jeb66UTo9ySLlZQEJ9PYl7pNa5qzudUnrbKuXHWuWLI,2382
727
+ qontract_reconcile-0.10.1rc677.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
728
+ qontract_reconcile-0.10.1rc677.dist-info/entry_points.txt,sha256=rIxI5zWtHNlfpDeq1a7pZXAPoqf7HG32KMTN3MeWK_8,429
729
+ qontract_reconcile-0.10.1rc677.dist-info/top_level.txt,sha256=l5ISPoXzt0SdR4jVdkfa7RPSKNc8zAHYWAnR-Dw8Ey8,24
730
+ qontract_reconcile-0.10.1rc677.dist-info/RECORD,,
@@ -1,3 +1,4 @@
1
+ import json
1
2
  import sys
2
3
  from collections.abc import (
3
4
  Callable,
@@ -7,7 +8,7 @@ from typing import (
7
8
  Any,
8
9
  )
9
10
 
10
- from pydantic import validator
11
+ from pydantic import BaseModel, root_validator, validator
11
12
 
12
13
  from reconcile.gql_definitions.aws_saml_roles.aws_accounts import (
13
14
  AWSAccountV1,
@@ -15,15 +16,13 @@ from reconcile.gql_definitions.aws_saml_roles.aws_accounts import (
15
16
  from reconcile.gql_definitions.aws_saml_roles.aws_accounts import (
16
17
  query as aws_accounts_query,
17
18
  )
18
- from reconcile.gql_definitions.aws_saml_roles.aws_groups import (
19
- AWSGroupV1,
20
- )
21
- from reconcile.gql_definitions.aws_saml_roles.aws_groups import (
22
- query as aws_groups_query,
19
+ from reconcile.gql_definitions.aws_saml_roles.roles import (
20
+ query as roles_query,
23
21
  )
24
22
  from reconcile.status import ExitCodes
25
23
  from reconcile.utils import gql
26
24
  from reconcile.utils.aws_api import AWSApi
25
+ from reconcile.utils.aws_helper import unique_sso_aws_accounts
27
26
  from reconcile.utils.defer import defer
28
27
  from reconcile.utils.disabled_integrations import integration_is_enabled
29
28
  from reconcile.utils.runtime.integration import (
@@ -54,6 +53,82 @@ class AwsSamlRolesIntegrationParams(PydanticRunParams):
54
53
  raise ValueError("max_session_duration_hours must be between 1 and 12 hours")
55
54
 
56
55
 
56
+ class CustomPolicy(BaseModel):
57
+ name: str
58
+ policy: dict[str, Any]
59
+
60
+ @validator("name")
61
+ def name_size(cls, v: str) -> str:
62
+ """Check the policy name size.
63
+
64
+ See https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_iam-quotas.html
65
+ """
66
+ if len(v) > 128:
67
+ raise ValueError(
68
+ f"The policy name '{v}' is too long. The AWS policy name must be 128 characters or less."
69
+ )
70
+ return v
71
+
72
+ @validator("policy")
73
+ def policy_size(cls, v: dict[str, Any]) -> dict[str, Any]:
74
+ """Check the policy size.
75
+
76
+ See https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_iam-quotas.html
77
+ """
78
+ if len(json.dumps(v, separators=(",", ":"))) > 6144:
79
+ raise ValueError(
80
+ f"The policy document '{v}' is too large. AWS policy documents must be 6144 characters or less (w/o white spaces)."
81
+ )
82
+ return v
83
+
84
+
85
+ class ManagedPolicy(BaseModel):
86
+ name: str
87
+
88
+
89
+ class AwsRole(BaseModel):
90
+ name: str
91
+ account: str
92
+ custom_policies: list[CustomPolicy]
93
+ managed_policies: list[ManagedPolicy]
94
+
95
+ @validator("name")
96
+ def name_size(cls, v: str) -> str:
97
+ """Check the role name size.
98
+
99
+ See https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_iam-quotas.html
100
+ """
101
+ if len(v) > 64:
102
+ raise ValueError(
103
+ f"The role name '{v}' is too long. The AWS role name must be 64 characters or less."
104
+ )
105
+ return v
106
+
107
+ @root_validator
108
+ def validate_policies(cls, values: dict[str, Any]) -> dict[str, Any]:
109
+ """Check the policies.
110
+
111
+ See https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_iam-quotas.html
112
+ """
113
+ custom_policies = values.get("custom_policies", [])
114
+ managed_policies = values.get("managed_policies", [])
115
+ if len(custom_policies) + len(managed_policies) > 20:
116
+ raise ValueError(
117
+ f"The role '{values['name']}' has too many policies. AWS roles can have at most 20 policies (via quota increase). Please consider consolidating the policies."
118
+ )
119
+ cp_names = [cp.name for cp in custom_policies]
120
+ if len(set(cp_names)) != len(cp_names):
121
+ raise ValueError(
122
+ f"The role '{values['name']}' has duplicate custom policies."
123
+ )
124
+ mp_names = [mp.name for mp in managed_policies]
125
+ if len(set(mp_names)) != len(mp_names):
126
+ raise ValueError(
127
+ f"The role '{values['name']}' has duplicate managed policies."
128
+ )
129
+ return values
130
+
131
+
57
132
  class AwsSamlRolesIntegration(
58
133
  QontractReconcileIntegration[AwsSamlRolesIntegrationParams]
59
134
  ):
@@ -70,7 +145,7 @@ class AwsSamlRolesIntegration(
70
145
  if not query_func:
71
146
  query_func = gql.get_api().query
72
147
  return {
73
- "aws_groups": [c.dict() for c in self.get_aws_groups(query_func)],
148
+ "roles": [c.dict() for c in self.get_roles(query_func)],
74
149
  }
75
150
 
76
151
  def get_aws_accounts(
@@ -85,40 +160,69 @@ class AwsSamlRolesIntegration(
85
160
  and (not account_name or account.name == account_name)
86
161
  ]
87
162
 
88
- def get_aws_groups(
163
+ def get_roles(
89
164
  self, query_func: Callable, account_name: str | None = None
90
- ) -> list[AWSGroupV1]:
91
- """Get all AWS groups with SSO enabled."""
92
- data = aws_groups_query(query_func)
93
- return [
94
- group
95
- for group in data.aws_groups or []
96
- if integration_is_enabled(self.name, group.account)
97
- and (not account_name or group.account.name == account_name)
98
- and group.account.sso
99
- and group.roles
100
- and group.policies
101
- and any(role.users for role in group.roles)
102
- ]
165
+ ) -> list[AwsRole]:
166
+ """Return all roles with AWS account relations."""
167
+ aws_roles = []
168
+ for role in roles_query(query_func).roles or []:
169
+ if not role.aws_groups and not role.user_policies:
170
+ continue
171
+
172
+ user_policies = role.user_policies or []
173
+ aws_groups = role.aws_groups or []
174
+ for sso_aws_account in unique_sso_aws_accounts(
175
+ integration=self.name,
176
+ accounts=[i.account for i in user_policies + aws_groups],
177
+ account_name=account_name,
178
+ ):
179
+ # AWS limits are checked via pydantic validators
180
+ custom_policies = [
181
+ CustomPolicy(name=user_policy.name, policy=user_policy.policy)
182
+ for user_policy in user_policies
183
+ if user_policy.account.uid == sso_aws_account.uid
184
+ ]
185
+ managed_policies = [
186
+ ManagedPolicy(name=p)
187
+ for aws_group in aws_groups
188
+ if aws_group.account.uid == sso_aws_account.uid
189
+ for p in aws_group.policies or []
190
+ ]
191
+
192
+ aws_roles.append(
193
+ AwsRole(
194
+ name=f"{sso_aws_account.uid}-{role.name}",
195
+ account=sso_aws_account.name,
196
+ custom_policies=custom_policies,
197
+ managed_policies=managed_policies,
198
+ )
199
+ )
200
+
201
+ return aws_roles
103
202
 
104
203
  def populate_saml_iam_roles(
105
- self, ts: TerrascriptClient, aws_groups: Iterable[AWSGroupV1]
204
+ self, ts: TerrascriptClient, aws_roles: Iterable[AwsRole]
106
205
  ) -> None:
107
206
  """Populate the SAML IAM roles."""
108
- for group in aws_groups:
109
- # aws groups without policies are filtered out by the query
110
- # duplicated policies aren't allowed in the same role
111
- policies = group.policies or []
112
- if len(policies) != len(set(policies)):
113
- raise ValueError(
114
- f"Group {group.name} has duplicated policies: {policies}"
115
- )
116
-
207
+ unique_policies = {
208
+ (role.account, custom_policy.name): custom_policy.policy
209
+ for role in aws_roles
210
+ for custom_policy in role.custom_policies
211
+ }
212
+ # User policies are unique per account
213
+ for (account, policy), policy_doc in unique_policies.items():
214
+ ts.populate_iam_policy(
215
+ account=account,
216
+ name=policy,
217
+ policy=policy_doc,
218
+ )
219
+ for role in aws_roles:
117
220
  ts.populate_saml_iam_role(
118
- account=group.account.name,
119
- name=group.name,
221
+ account=role.account,
222
+ name=role.name,
120
223
  saml_provider_name=self.params.saml_idp_name,
121
- policies=policies,
224
+ aws_managed_policies=[p.name for p in role.managed_policies],
225
+ customer_managed_policies=[p.name for p in role.custom_policies],
122
226
  max_session_duration_hours=self.params.max_session_duration_hours,
123
227
  )
124
228
 
@@ -130,9 +234,7 @@ class AwsSamlRolesIntegration(
130
234
  gql_api.query, account_name=self.params.account_name
131
235
  )
132
236
  aws_accounts_dict = [account.dict(by_alias=True) for account in aws_accounts]
133
- aws_groups = self.get_aws_groups(
134
- gql_api.query, account_name=self.params.account_name
135
- )
237
+ aws_roles = self.get_roles(gql_api.query, account_name=self.params.account_name)
136
238
 
137
239
  ts = TerrascriptClient(
138
240
  self.name.replace("-", "_"),
@@ -141,7 +243,7 @@ class AwsSamlRolesIntegration(
141
243
  aws_accounts_dict,
142
244
  secret_reader=self.secret_reader,
143
245
  )
144
- self.populate_saml_iam_roles(ts, aws_groups)
246
+ self.populate_saml_iam_roles(ts, aws_roles)
145
247
  working_dirs = ts.dump(print_to_file=self.params.print_to_file)
146
248
 
147
249
  if self.params.print_to_file:
@@ -17,25 +17,35 @@ from pydantic import ( # noqa: F401 # pylint: disable=W0611
17
17
  Json,
18
18
  )
19
19
 
20
+ from reconcile.gql_definitions.fragments.aws_account_sso import AWSAccountSSO
21
+
20
22
 
21
23
  DEFINITION = """
22
- query AwsSamlRolesAwsGroupQuery {
23
- aws_groups: awsgroups_v1 {
24
+ fragment AWSAccountSSO on AWSAccount_v1 {
25
+ name
26
+ uid
27
+ sso
28
+ disable {
29
+ integrations
30
+ }
31
+ }
32
+
33
+ query AwsSamlRolesQuery {
34
+ roles: roles_v1 {
24
35
  name
25
- account {
36
+ user_policies {
26
37
  name
27
- uid
28
- sso
29
- disable {
30
- integrations
38
+ policy
39
+ account {
40
+ ...AWSAccountSSO
31
41
  }
32
42
  }
33
- roles {
34
- users {
35
- org_username
43
+ aws_groups {
44
+ account {
45
+ ...AWSAccountSSO
36
46
  }
47
+ policies
37
48
  }
38
- policies
39
49
  }
40
50
  }
41
51
  """
@@ -47,37 +57,28 @@ class ConfiguredBaseModel(BaseModel):
47
57
  extra=Extra.forbid
48
58
 
49
59
 
50
- class DisableClusterAutomationsV1(ConfiguredBaseModel):
51
- integrations: Optional[list[str]] = Field(..., alias="integrations")
52
-
53
-
54
- class AWSAccountV1(ConfiguredBaseModel):
60
+ class AWSUserPolicyV1(ConfiguredBaseModel):
55
61
  name: str = Field(..., alias="name")
56
- uid: str = Field(..., alias="uid")
57
- sso: Optional[bool] = Field(..., alias="sso")
58
- disable: Optional[DisableClusterAutomationsV1] = Field(..., alias="disable")
62
+ policy: Json = Field(..., alias="policy")
63
+ account: AWSAccountSSO = Field(..., alias="account")
59
64
 
60
65
 
61
- class UserV1(ConfiguredBaseModel):
62
- org_username: str = Field(..., alias="org_username")
66
+ class AWSGroupV1(ConfiguredBaseModel):
67
+ account: AWSAccountSSO = Field(..., alias="account")
68
+ policies: Optional[list[str]] = Field(..., alias="policies")
63
69
 
64
70
 
65
71
  class RoleV1(ConfiguredBaseModel):
66
- users: list[UserV1] = Field(..., alias="users")
67
-
68
-
69
- class AWSGroupV1(ConfiguredBaseModel):
70
72
  name: str = Field(..., alias="name")
71
- account: AWSAccountV1 = Field(..., alias="account")
72
- roles: Optional[list[RoleV1]] = Field(..., alias="roles")
73
- policies: Optional[list[str]] = Field(..., alias="policies")
73
+ user_policies: Optional[list[AWSUserPolicyV1]] = Field(..., alias="user_policies")
74
+ aws_groups: Optional[list[AWSGroupV1]] = Field(..., alias="aws_groups")
74
75
 
75
76
 
76
- class AwsSamlRolesAwsGroupQueryQueryData(ConfiguredBaseModel):
77
- aws_groups: Optional[list[AWSGroupV1]] = Field(..., alias="aws_groups")
77
+ class AwsSamlRolesQueryQueryData(ConfiguredBaseModel):
78
+ roles: Optional[list[RoleV1]] = Field(..., alias="roles")
78
79
 
79
80
 
80
- def query(query_func: Callable, **kwargs: Any) -> AwsSamlRolesAwsGroupQueryQueryData:
81
+ def query(query_func: Callable, **kwargs: Any) -> AwsSamlRolesQueryQueryData:
81
82
  """
82
83
  This is a convenience function which queries and parses the data into
83
84
  concrete types. It should be compatible with most GQL clients.
@@ -90,7 +91,7 @@ def query(query_func: Callable, **kwargs: Any) -> AwsSamlRolesAwsGroupQueryQuery
90
91
  kwargs: optional arguments that will be passed to the query function
91
92
 
92
93
  Returns:
93
- AwsSamlRolesAwsGroupQueryQueryData: queried data parsed into generated classes
94
+ AwsSamlRolesQueryQueryData: queried data parsed into generated classes
94
95
  """
95
96
  raw_data: dict[Any, Any] = query_func(DEFINITION, **kwargs)
96
- return AwsSamlRolesAwsGroupQueryQueryData(**raw_data)
97
+ return AwsSamlRolesQueryQueryData(**raw_data)
@@ -843,13 +843,8 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
843
843
  for user_policy in user_policies:
844
844
  policy_name = user_policy["name"]
845
845
  account_name = user_policy["account"]["name"]
846
- account_uid = user_policy["account"]["uid"]
847
846
  for user in users:
848
- # replace known keys with values
849
847
  user_name = self._get_aws_username(user)
850
- policy = user_policy["policy"]
851
- policy = policy.replace("${aws:username}", user_name)
852
- policy = policy.replace("${aws:accountid}", account_uid)
853
848
 
854
849
  # Ref: terraform aws_iam_policy
855
850
  tf_iam_user = self.get_tf_iam_user(user_name)
@@ -857,7 +852,7 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
857
852
  tf_aws_iam_policy = aws_iam_policy(
858
853
  identifier,
859
854
  name=identifier,
860
- policy=policy,
855
+ policy=user_policy["policy"],
861
856
  )
862
857
  self.add_resource(account_name, tf_aws_iam_policy)
863
858
  # Ref: terraform aws_iam_user_policy_attachment
@@ -2569,18 +2564,29 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
2569
2564
 
2570
2565
  self.add_resources(account, tf_resources)
2571
2566
 
2567
+ def populate_iam_policy(self, account: str, name: str, policy: dict[str, Any]):
2568
+ tf_aws_iam_policy = aws_iam_policy(
2569
+ f"{account}-{name}", name=name, policy=json.dumps(policy)
2570
+ )
2571
+ self.add_resource(account, tf_aws_iam_policy)
2572
+
2572
2573
  def populate_saml_iam_role(
2573
2574
  self,
2574
2575
  account: str,
2575
2576
  name: str,
2576
2577
  saml_provider_name: str,
2577
- policies: list[str],
2578
+ aws_managed_policies: list[str],
2579
+ customer_managed_policies: list[str] | None = None,
2578
2580
  max_session_duration_hours: int = 1,
2579
2581
  ) -> None:
2580
2582
  """Manage the an IAM role needed for SAML authentication."""
2581
2583
  managed_policy_arns = [
2582
- f"arn:{self._get_partition(account)}:" + f"iam::aws:policy/{policy}"
2583
- for policy in policies
2584
+ f"arn:{self._get_partition(account)}:iam::aws:policy/{policy}"
2585
+ for policy in aws_managed_policies
2586
+ ]
2587
+ managed_policy_arns += [
2588
+ f"arn:{self._get_partition(account)}:iam::{self.uids[account]}:policy/{policy}"
2589
+ for policy in customer_managed_policies or []
2584
2590
  ]
2585
2591
  assume_role_policy = {
2586
2592
  "Version": "2012-10-17",
@@ -2601,7 +2607,7 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
2601
2607
  }
2602
2608
  role_tf_resource = aws_iam_role(
2603
2609
  f"{account}-{name}",
2604
- name=f"{self.uids[account]}-{name}",
2610
+ name=name,
2605
2611
  assume_role_policy=json.dumps(assume_role_policy),
2606
2612
  managed_policy_arns=managed_policy_arns,
2607
2613
  max_session_duration=max_session_duration_hours * 3600,