Skip to content

Commit

Permalink
Merge branch 'mr/kanya/update' into 'master'
Browse files Browse the repository at this point in the history
Add inline policies on IAM Roles

See merge request it/e3-aws!10
  • Loading branch information
RomaricKanyamibwa committed Aug 28, 2024
2 parents 6065641 + f53219b commit 89f69e6
Show file tree
Hide file tree
Showing 3 changed files with 144 additions and 2 deletions.
36 changes: 35 additions & 1 deletion src/e3/aws/troposphere/iam/role.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,12 @@
from e3.aws import name_to_id
from e3.aws.troposphere import Construct
from e3.aws.troposphere.iam.policy_document import PolicyDocument
from e3.aws.troposphere.iam.policy_statement import AssumeRole, Trust, Allow
from e3.aws.troposphere.iam.policy_statement import (
AssumeRole,
Trust,
Allow,
PolicyStatement,
)

if TYPE_CHECKING:
from e3.aws.troposphere import Stack
Expand All @@ -34,6 +39,9 @@ class Role(Construct):
for the role.
:param condition: condition contains statements that define the circumstances
under which role the is created.
:param inline_policies: a dict of inline policy documents that are embedded in
the role, the keys are the names of the policies and the values are the
policy documents. They can be added or updated
"""

name: str
Expand All @@ -45,6 +53,7 @@ class Role(Construct):
path: str = "/"
boundary: str | None = None
condition: dict[str, dict] | None = None
inline_policies: dict[str, PolicyDocument | PolicyStatement | dict] | None = None

@property
def trust_policy(self) -> PolicyDocument:
Expand All @@ -56,6 +65,30 @@ def trust_policy(self) -> PolicyDocument:
else:
return PolicyDocument(statements=[AssumeRole(principal=self.trust)])

@property
def policies(self) -> list[iam.Policy] | None:
"""Return inline policies."""
if not self.inline_policies:
return None

policies = []
for policy_name, policy_document in self.inline_policies.items():
args: dict[str, str | dict | PolicyStatement | PolicyDocument] = {}
args["PolicyName"] = policy_name
if isinstance(policy_document, dict):
args["PolicyDocument"] = policy_document

elif isinstance(policy_document, PolicyDocument):
args["PolicyDocument"] = policy_document.as_dict

elif isinstance(policy_document, PolicyStatement):
args["PolicyDocument"] = PolicyDocument(
statements=[policy_document]
).as_dict

policies.append(iam.Policy(**args))
return policies

@property
def arn(self):
return GetAtt(name_to_id(self.name), "Arn")
Expand All @@ -74,6 +107,7 @@ def resources(self, stack: Stack) -> list[AWSObject]:
"Path": self.path,
"PermissionsBoundary": self.boundary,
"Condition": self.condition,
"Policies": self.policies,
}.items():
if val is not None:
attr[key] = val
Expand Down
35 changes: 34 additions & 1 deletion tests/tests_e3_aws/troposphere/iam/iam_test.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
"""Provide IAM construct tests."""

from e3.aws.troposphere.iam.role import Role
import os
import json
from e3.aws.troposphere.iam.role import Role, PolicyDocument
from e3.aws.troposphere.iam.policy_statement import Allow, Trust
from e3.aws.troposphere import Stack

TEST_DIR = os.path.dirname(os.path.abspath(__file__))
EXPECTED_ROLE = {
"TestRole": {
"Properties": {
Expand Down Expand Up @@ -97,3 +100,33 @@ def test_trust_roles(stack: Stack) -> None:
)
)
assert stack.export()["Resources"] == EXPECTED_TRUST_ROLES


def test_role_with_inline(stack: Stack) -> None:
stack.add(
Role(
name="TestRoleWithPolicies",
description="TestRoleWithPolicies description",
trust=Trust(services=["ec2"]),
inline_policies={
"PolicyDocument": PolicyDocument(
statements=[
Allow(action="iam:*", resource="*"),
Allow(action="logs:*", resource="*"),
]
),
"PolicyStatement": Allow(action="s3:Get*"),
"Dict": {
"Version": "2012-10-17",
"Statement": [
{"Effect": "Allow", "Action": "ec2:Describe*", "Resource": "*"}
],
},
},
)
)

with open(os.path.join(TEST_DIR, "role_with_inline.json")) as fd:
expected_stack = json.load(fd)

assert stack.export()["Resources"] == expected_stack
75 changes: 75 additions & 0 deletions tests/tests_e3_aws/troposphere/iam/role_with_inline.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
{
"TestRoleWithPolicies": {
"Properties": {
"RoleName": "TestRoleWithPolicies",
"Description": "TestRoleWithPolicies description",
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "sts:AssumeRole",
"Principal": {
"Service": [
"ec2.amazonaws.com"
]
}
}
]
},
"Tags": [
{
"Key": "Name",
"Value": "TestRoleWithPolicies"
}
],
"Path": "/",
"Policies": [
{
"PolicyName": "PolicyDocument",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "iam:*",
"Resource": "*"
},
{
"Effect": "Allow",
"Action": "logs:*",
"Resource": "*"
}
]
}
},
{
"PolicyName": "PolicyStatement",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "s3:Get*"
}
]
}
},
{
"PolicyName": "Dict",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ec2:Describe*",
"Resource": "*"
}
]
}
}
]
},
"Type": "AWS::IAM::Role"
}
}

0 comments on commit 89f69e6

Please sign in to comment.