CrossAccountPolicyForIAMJob implements FullstopJob { @Scheduled( fixedRate = 1000 * 60 * 150, initialDelay = 1000 * 60 * 15 ) public void run() { log.info("Running job {}", getClass().getSimpleName()); for (final String account : allAccountIds.get()) { try { final AmazonIdentityManagementClient iamClient = clientProvider.getClient( AmazonIdentityManagementClient.class, account, getRegion(EU_WEST_1) ); Optional<String> nextMarker = Optional.empty(); do { final ListRolesRequest request = new ListRolesRequest(); nextMarker.ifPresent(request::setMarker); final ListRolesResult listRolesResult = iamClient.listRoles(request); nextMarker = Optional.ofNullable(trimToNull(listRolesResult.getMarker())); for (final Role role : listRolesResult.getRoles()) { final String assumeRolePolicyDocument = role.getAssumeRolePolicyDocument(); List<String> principals = Lists.newArrayList(); try { principals = JsonPath.read(URLDecoder.decode(assumeRolePolicyDocument, "UTF-8"), ".Statement[*].Principal.AWS"); } catch (final UnsupportedEncodingException e) { log.warn("Could not decode assumeRolePolicyDocument", e); } final Set<String> allowedAccounts = newHashSet(account, jobsProperties.getManagementAccount()); final List<String> crossAccountArns = principals.stream() .map(ARN_PATTERN::matcher) .filter(Matcher::matches) .filter(m -> !allowedAccounts.contains(m.group("accountId"))) .map(Matcher::group) .collect(toList()); if (crossAccountArns != null && !crossAccountArns.isEmpty()) { writeViolation( account, ImmutableMap.of( "role_arn", role.getArn(), "role_name", role.getRoleName(), "grantees", crossAccountArns), role.getRoleId() ); } } } while (nextMarker.isPresent()); } catch (Exception e) { jobExceptionHandler.onException(e, ImmutableMap.of( "job", this.getClass().getSimpleName(), "aws_account_id", account)); } } log.info("Completed job {}", getClass().getSimpleName()); } @Autowired  CrossAccountPolicyForIAMJob(final ViolationSink violationSink,
                                       final ClientProvider clientProvider,
                                       final AccountIdSupplier allAccountIds,
                                       final JobsProperties jobsProperties,
                                       final JobExceptionHandler jobExceptionHandler); @PostConstruct void init(); @Scheduled( fixedRate = 1000 * 60 * 150, // 2.5 hours initialDelay = 1000 * 60 * 15 // 15 minutes ) void run();  }
@Test public void testCheck() throws Exception { when(accountIdSupplierMock.get()).thenReturn(newHashSet(ACCOUNT_ID)); when(jobsPropertiesMock.getManagementAccount()).thenReturn(MANAGEMENT_ACCOUNT); when(mockAmazonIdentityManagementClient.listRoles(any(ListRolesRequest.class))).thenReturn(mockListRolesResult); final CrossAccountPolicyForIAMJob crossAccountPolicyForIAMJob = new CrossAccountPolicyForIAMJob( violationSinkMock, clientProviderMock, accountIdSupplierMock, jobsPropertiesMock, mock(JobExceptionHandler.class)); crossAccountPolicyForIAMJob.run(); verify(accountIdSupplierMock).get(); verify(clientProviderMock).getClient(any(), any(String.class), any(Region.class)); verify(mockAmazonIdentityManagementClient).listRoles(any(ListRolesRequest.class)); verify(jobsPropertiesMock, atLeastOnce()).getManagementAccount(); verify(violationSinkMock, times(1)).put(argThat(ViolationMatchers.hasType(CROSS_ACCOUNT_ROLE))); }