Skip to content

Commit e4b02a5

Browse files
authored
fix: apply permissions boundary (#231)
2 parents 9aa3311 + 7db6adc commit e4b02a5

File tree

2 files changed

+62
-4
lines changed

2 files changed

+62
-4
lines changed

app.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
#!/usr/bin/env python3
22
""" CDK Configuration for the veda-backend stack."""
33

4-
from aws_cdk import App, Stack, Tags, aws_iam
4+
from aws_cdk import App, Aspects, Stack, Tags, aws_iam
55
from constructs import Construct
66

77
from config import veda_app_settings
88
from database.infrastructure.construct import RdsConstruct
99
from domain.infrastructure.construct import DomainConstruct
1010
from network.infrastructure.construct import VpcConstruct
11+
from permissions_boundary.infrastructure.construct import PermissionsBoundaryAspect
1112
from raster_api.infrastructure.construct import RasterApiLambdaConstruct
1213
from stac_api.infrastructure.construct import StacApiLambdaConstruct
1314

@@ -22,12 +23,13 @@ def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
2223
super().__init__(scope, construct_id, **kwargs)
2324

2425
if veda_app_settings.permissions_boundary_policy_name:
25-
permission_boundary_policy = aws_iam.Policy.from_policy_name(
26+
permissions_boundary_policy = aws_iam.Policy.from_policy_name(
2627
self,
27-
"permission-boundary",
28+
"permissions-boundary",
2829
veda_app_settings.permissions_boundary_policy_name,
2930
)
30-
aws_iam.PermissionsBoundary.of(self).apply(permission_boundary_policy)
31+
aws_iam.PermissionsBoundary.of(self).apply(permissions_boundary_policy)
32+
Aspects.of(self).add(PermissionsBoundaryAspect(permissions_boundary_policy))
3133

3234

3335
veda_stack = VedaStack(
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
"""Class that applies permissions boundary to all the roles created within a Stack"""
2+
from typing import Union
3+
4+
import jsii
5+
from aws_cdk import IAspect, aws_iam
6+
from constructs import IConstruct
7+
from jsii._reference_map import _refs
8+
from jsii._utils import Singleton
9+
10+
11+
@jsii.implements(IAspect)
12+
class PermissionsBoundaryAspect:
13+
"""
14+
This aspect finds all aws_iam.Role objects in a node (ie. CDK stack) and sets permissions boundary to the given ARN.
15+
"""
16+
17+
def __init__(self, permissions_boundary: Union[aws_iam.ManagedPolicy, str]) -> None:
18+
"""
19+
:param permissions_boundary: Either aws_iam.ManagedPolicy object or managed policy's ARN string
20+
"""
21+
self.permissions_boundary = permissions_boundary
22+
23+
def visit(self, construct_ref: IConstruct) -> None:
24+
"""
25+
construct_ref only contains a string reference to an object. To get the actual object, we need to resolve it using JSII mapping.
26+
:param construct_ref: ObjRef object with string reference to the actual object.
27+
:return: None
28+
"""
29+
if isinstance(construct_ref, jsii._kernel.ObjRef) and hasattr(
30+
construct_ref, "ref"
31+
):
32+
kernel = Singleton._instances[
33+
jsii._kernel.Kernel
34+
] # The same object is available as: jsii.kernel
35+
resolve = _refs.resolve(kernel, construct_ref)
36+
else:
37+
resolve = construct_ref
38+
39+
def _walk(obj):
40+
if isinstance(obj, aws_iam.Role):
41+
cfn_role = obj.node.find_child("Resource")
42+
policy_arn = (
43+
self.permissions_boundary
44+
if isinstance(self.permissions_boundary, str)
45+
else self.permissions_boundary.managed_policy_arn
46+
)
47+
cfn_role.add_property_override("PermissionsBoundary", policy_arn)
48+
else:
49+
if hasattr(obj, "permissions_node"):
50+
for c in obj.permissions_node.children:
51+
_walk(c)
52+
if hasattr(obj, "node") and obj.node.children:
53+
for c in obj.node.children:
54+
_walk(c)
55+
56+
_walk(resolve)

0 commit comments

Comments
 (0)