Skip to content

Commit b2c08ac

Browse files
committed
adds source filtering for who_can
1 parent 3675cc0 commit b2c08ac

1 file changed

Lines changed: 50 additions & 1 deletion

File tree

iamspy/model.py

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,50 @@ def get_correct_case_principal(self, principal: str) -> str:
397397

398398
return entity.Arn
399399

400+
def _check_viable_source_accounts(self, action: str, resource: str) -> Set[str]:
401+
print("Checking now")
402+
all_source_accounts = list(self._model.gaads.keys())
403+
try:
404+
if resource.startswith("arn:aws:s3:::") and "/" in resource:
405+
bucket = resource.split("/")[0]
406+
rp = [p for p in self._model.resource_policies if p.Resource == bucket]
407+
else:
408+
rp = [p for p in self._model.resource_policies if p.Resource == resource]
409+
except StopIteration:
410+
# No resource policy, assume same account only (unless it's an S3 bucket)
411+
if resource.startswith("arn:aws:s3:::"):
412+
return set(all_source_accounts)
413+
else:
414+
return set([resource.split(":")[4]])
415+
416+
solver = self.generate_solver(
417+
source=None,
418+
action=action,
419+
resource=resource,
420+
)
421+
solver.add(z3.Bool("identity") == True)
422+
solver.add(
423+
z3.Or(
424+
*[
425+
z3.And(
426+
parse_string(z3.String("s"), f"arn:aws:iam::{account}:*"),
427+
z3.String(f"s_account") == z3.StringVal(account),
428+
)
429+
for account in all_source_accounts
430+
]
431+
)
432+
)
433+
434+
accounts = set()
435+
while solver.check() == z3.sat:
436+
m = solver.model()
437+
account = str(m[z3.String("s_account")])[1:-1]
438+
accounts.add(account)
439+
solver.add(z3.String("s_account") != z3.StringVal(account))
440+
441+
logger.debug(f"Viable source accounts for {resource} are: {accounts}")
442+
return accounts
443+
400444
def _can_i(
401445
self,
402446
source: str,
@@ -514,8 +558,13 @@ def who_can(
514558
"""
515559
Used by the CLI to provide the who-can call.
516560
"""
561+
possible_accounts = self._check_viable_source_accounts(action, resource)
562+
517563
for gaad in self._model.gaads.values():
518-
print(f"Checking identities in {gaad.account} GAAD")
564+
if gaad.account not in possible_accounts:
565+
logger.debug(f"Skipping {gaad.account} GAAD as not a viable source account for {resource}")
566+
continue
567+
logger.debug(f"Checking identities in {gaad.account} GAAD")
519568
sources = set()
520569
for identity in gaad.RoleDetailList + gaad.UserDetailList:
521570
sources.add(identity.Arn)

0 commit comments

Comments
 (0)