@@ -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