@@ -24,7 +24,7 @@ import relations from '../enums/relations'
2424import { Credentials } from '../types'
2525import { obfuscateSensitiveString } from '../utils/format'
2626import { checkAndMergeConnections } from '../utils'
27- import { Account , rawDataInterface } from './base'
27+ import { Account , rawDataInterface , rawDataResponseInterface } from './base'
2828import enhancers , { EnhancerConfig } from './base/enhancers'
2929import AwsErrorLog from '../utils/errorLog'
3030
@@ -53,28 +53,35 @@ export default class Provider extends CloudGraph.Client {
5353
5454 private properties : {
5555 services : { [ key : string ] : string }
56- regions : string [ ]
5756 resources : { [ key : string ] : string }
5857 }
5958
60- logSelectedAccessRegionsAndResources (
59+ logSelectedAccessResources (
6160 profilesOrRolesToLog : string [ ] ,
62- regionsToLog : string ,
63- resourcesToLog : string
61+ resourcesToLog : string ,
6462 ) : void {
6563 this . logger . info (
6664 `Profiles and role ARNs configured: ${ chalk . green (
6765 profilesOrRolesToLog . join ( ', ' )
6866 ) } `
6967 )
70- this . logger . info (
71- `Regions configured: ${ chalk . green ( regionsToLog . replace ( / , / g, ', ' ) ) } `
72- )
7368 this . logger . info (
7469 `Resources configured: ${ chalk . green ( resourcesToLog . replace ( / , / g, ', ' ) ) } `
7570 )
7671 }
7772
73+ logSelectedRegions ( regions : string | undefined ) : void {
74+ if ( regions ) {
75+ this . logger . info (
76+ `Regions configured: ${ chalk . green ( regions . replace ( / , / g, ', ' ) ) } `
77+ )
78+ } else {
79+ this . logger . info (
80+ 'Active regions will be detected automatically during the scan.'
81+ )
82+ }
83+ }
84+
7885 // TODO: update to also support ignorePrompts config
7986 async configure ( ) : Promise < { [ key : string ] : any } > {
8087 const { flags = { } , cloudGraphConfig, ...providerSettings } = this . config
@@ -178,12 +185,10 @@ export default class Provider extends CloudGraph.Client {
178185 ] )
179186 this . logger . debug ( `Regions selected: ${ regionsAnswer } ` )
180187 if ( ! regionsAnswer . length ) {
188+ result . regions = undefined
181189 this . logger . info (
182- `No Regions selected, using default region: ${ chalk . green (
183- DEFAULT_REGION
184- ) } `
190+ `No Regions selected, active regions will be detected automatically.`
185191 )
186- result . regions = DEFAULT_REGION
187192 } else {
188193 result . regions = regionsAnswer . join ( ',' )
189194 }
@@ -218,11 +223,11 @@ export default class Provider extends CloudGraph.Client {
218223 'AWS'
219224 ) } configuration successfully completed ${ confettiBall } `
220225 )
221- this . logSelectedAccessRegionsAndResources (
226+ this . logSelectedAccessResources (
222227 result . accounts . map ( acct => acct . roleArn ?? acct . profile ) ,
223- result . regions ,
224228 result . resources
225229 )
230+ this . logSelectedRegions ( result . regions )
226231
227232 return result
228233 }
@@ -573,15 +578,9 @@ export default class Provider extends CloudGraph.Client {
573578 private async getRawData (
574579 account : Account ,
575580 opts ?: Opts
576- ) : Promise < rawDataInterface [ ] > {
577- let { regions : configuredRegions , resources : configuredResources } =
578- this . config
581+ ) : Promise < rawDataResponseInterface > {
582+ let { resources : configuredResources } = this . config
579583 const result : rawDataInterface [ ] = [ ]
580- if ( ! configuredRegions ) {
581- configuredRegions = this . properties . regions . join ( ',' )
582- } else {
583- configuredRegions = [ ...new Set ( configuredRegions . split ( ',' ) ) ] . join ( ',' )
584- }
585584 if ( ! configuredResources ) {
586585 configuredResources = Object . values ( this . properties . services ) . join ( ',' )
587586 }
@@ -591,6 +590,7 @@ export default class Provider extends CloudGraph.Client {
591590
592591 const config = await this . getAwsConfig ( account )
593592 const { accountId } = await this . getIdentity ( account )
593+ const configuredRegions = await this . getRegions ( account )
594594 for ( const resource of resourceNames ) {
595595 const serviceClass = this . getService ( resource )
596596 if ( serviceClass && serviceClass . getData ) {
@@ -622,7 +622,7 @@ export default class Provider extends CloudGraph.Client {
622622 }
623623 }
624624 this . logger . success ( `Account: ${ accountId } scan completed` )
625- return result
625+ return { rawData : result , regions : configuredRegions . split ( ',' ) }
626626 }
627627
628628 private enhanceData ( { data, ...config } : EnhancerConfig ) : ProviderData {
@@ -655,7 +655,7 @@ export default class Provider extends CloudGraph.Client {
655655 entities : [ ] ,
656656 connections : { } ,
657657 }
658- let { regions : configuredRegions , resources : configuredResources } =
658+ let { resources : configuredResources } =
659659 this . config
660660 const {
661661 accounts : configuredAccounts ,
@@ -664,25 +664,18 @@ export default class Provider extends CloudGraph.Client {
664664 accounts : Account [ ]
665665 cloudGraphConfig : { ignoreEnvVariables : boolean }
666666 } = this . config
667- if ( ! configuredRegions ) {
668- configuredRegions = this . properties . regions . join ( ',' )
669- } else {
670- configuredRegions = [ ...new Set ( configuredRegions . split ( ',' ) ) ] . join ( ',' )
671- }
672667 if ( ! configuredResources ) {
673668 configuredResources = Object . values ( this . properties . services ) . join ( ',' )
674669 }
675-
676670 const usingEnvCreds = ! ! process . env . AWS_ACCESS_KEY_ID && ! ignoreEnvVariables
677671
678- this . logSelectedAccessRegionsAndResources (
672+ this . logSelectedAccessResources (
679673 usingEnvCreds
680674 ? [ ENV_VAR_CREDS_LOG ]
681675 : configuredAccounts . map ( acct => {
682676 return acct . roleArn || acct . profile
683677 } ) ,
684- configuredRegions ,
685- configuredResources
678+ configuredResources ,
686679 )
687680
688681 // Leaving this here in case we need to test another service or to inject a logging function
@@ -692,6 +685,7 @@ export default class Provider extends CloudGraph.Client {
692685 // data so we can pass along accountId
693686 // TODO: find a better way to handle this
694687 let mergedRawData : rawDataInterface [ ] = [ ]
688+ let relevantRegions = new Set < string > ( )
695689 const globalRegion = 'aws-global'
696690 const tags = { className : 'Tag' , name : 'tag' , data : { [ globalRegion ] : [ ] } }
697691 const accounts = {
@@ -701,10 +695,13 @@ export default class Provider extends CloudGraph.Client {
701695 }
702696 // If the user has passed aws creds as env variables, dont use profile list
703697 if ( usingEnvCreds ) {
704- rawData = await this . getRawData (
698+ let { rawData : results , regions : activeRegions } = await this . getRawData (
705699 { profile : 'default' , roleArn : undefined , externalId : undefined } ,
706700 opts
707701 )
702+
703+ rawData = results
704+ relevantRegions = new Set ( [ ...relevantRegions , ...activeRegions ] )
708705 } else {
709706 const crawledAccounts = [ ]
710707 for ( const account of configuredAccounts ) {
@@ -721,13 +718,14 @@ export default class Provider extends CloudGraph.Client {
721718 }
722719 }
723720 const { accountId } = await this . getIdentity ( account )
724- accounts . data [ globalRegion ] . push ( {
725- id : accountId ,
726- regions : configuredRegions . split ( ',' ) ,
727- } )
728721 if ( ! crawledAccounts . find ( val => val === accountId ) ) {
729722 crawledAccounts . push ( accountId )
730- const newRawData = await this . getRawData ( account , opts )
723+ const { rawData : newRawData , regions} = await this . getRawData ( account , opts )
724+ relevantRegions = new Set ( [ ...relevantRegions , ...regions ] )
725+ accounts . data [ globalRegion ] . push ( {
726+ id : accountId ,
727+ regions : regions ,
728+ } )
731729 mergedRawData = this . mergeRawData ( mergedRawData , newRawData )
732730 rawData = [ ...rawData , ...newRawData ]
733731 } else {
@@ -797,7 +795,7 @@ export default class Provider extends CloudGraph.Client {
797795 if ( typeof serviceClass . getConnections === 'function' ) {
798796 // We need to loop through all configured regions here because services can be connected to things in another region
799797 let serviceConnections = { }
800- for ( const connectionRegion of configuredRegions . split ( ',' ) ) {
798+ for ( const connectionRegion of relevantRegions ) {
801799 const connections = serviceClass . getConnections ( {
802800 service,
803801 region : connectionRegion ,
@@ -865,10 +863,43 @@ export default class Provider extends CloudGraph.Client {
865863
866864 const enhancedData = this . enhanceData ( {
867865 accounts : accounts . data [ globalRegion ] ,
868- configuredRegions,
866+ configuredRegions : [ ... relevantRegions ] . join ( ',' ) ,
869867 rawData : mergedRawData ,
870868 data : result ,
871869 } )
872870 return { ...enhancedData , errors : AwsErrorLog . errorsHistory }
873871 }
872+
873+ /* Determine the list of regions to scan */
874+ private async getRegions ( account : Account ) : Promise < string > {
875+ let { regions : configuredRegions } = this . config
876+ if ( configuredRegions ) {
877+ configuredRegions = [ ...new Set ( configuredRegions . split ( ',' ) ) ] . join ( ',' )
878+ } else {
879+ configuredRegions = ( await this . getActiveRegions ( account ) ) . join ( ',' )
880+ }
881+
882+ this . logger . info (
883+ `Regions configured for profile ${ account . profile } : ${ chalk . green ( configuredRegions . replace ( / , / g, ', ' ) ) } `
884+ )
885+
886+ return configuredRegions
887+ }
888+
889+ /* Fetch the list of regions that are active for the account */
890+ private async getActiveRegions ( account : Account ) : Promise < string [ ] > {
891+ const config = await this . getAwsConfig ( account )
892+ // Assume a default region in order to get the list of enabled regions
893+ config . region = DEFAULT_REGION
894+ const ec2 = new AWS . EC2 ( config )
895+ const regions = await ec2
896+ . describeRegions ( {
897+ AllRegions : false ,
898+ } )
899+ . promise ( )
900+
901+ const activeRegions = await regions . Regions . map ( ( { RegionName } ) => RegionName )
902+
903+ return activeRegions
904+ }
874905}
0 commit comments