Repository: tenable/terrascan (language: python)

Issue:
Ensure remote modules are downloaded only once



Discussion / hints:

Fix patch:
diff --git a/docs/usage/command_line_mode.md b/docs/usage/command_line_mode.md
index 8d9477a53..7f33f4aac 100644
--- a/docs/usage/command_line_mode.md
+++ b/docs/usage/command_line_mode.md
@@ -205,6 +205,8 @@ aws_ecr_repository:
 | |scan-rules|Specify rules to scan, example: --scan-rules="ruleID1,ruleID2"|
 | |skip-rules|Specify one or more rules to skip while scanning. Example: --skip-rules="ruleID1,ruleID2"|
 | |use-colours |Configure the color for output (**auto**, t, f) |
+|--non-recursive |Use this for non recursive directories and modules scan | By default directory is scanned recursively, if this flag is used then only provided root directory will be scanned|
+|--use-terraform-cache |Use this to refer terraform remote modules from terraform init cache rather than downloading | By default remote module will be downloaded in temporary directory. If this flag is set then modules will be refered from terraform init cache if module is not present in terraform init cache it will be downloaded. Directory will be scanned non recurively if this flag is used.(applicable only with terraform IaC provider)|
 | -v | verbose | Displays violations with all details |
 
 | Global flags | Description | Options |
@@ -246,6 +248,7 @@ Flags:
       --show-passed               display passed rules, along with violations
       --skip-rules strings        one or more rules to skip while scanning (example: --skip-rules="ruleID1,ruleID2")
       --use-colors string         color output (auto, t, f) (default "auto")
+      --use-terraform-cache       use terraform init cache for remote modules (when used directory scan will be non recursive,flag applicable only with terraform IaC provider)
   -v, --verbose                   will show violations with details (applicable for default output)
 
 Global Flags:
diff --git a/go.mod b/go.mod
index b8399c6f7..2c9cef344 100644
--- a/go.mod
+++ b/go.mod
@@ -9,6 +9,7 @@ replace (
 )
 
 require (
+	github.com/BurntSushi/toml v0.4.0 // indirect
 	github.com/VerbalExpressions/GoVerbalExpressions v0.0.0-20200410162751-4d76a1099a6e
 	github.com/awslabs/goformation/v4 v4.19.1
 	github.com/ghodss/yaml v1.0.0
@@ -42,7 +43,7 @@ require (
 	github.com/zclconf/go-cty v1.8.3
 	go.uber.org/zap v1.16.0
 	golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c
-	golang.org/x/tools v0.1.4 // indirect
+	golang.org/x/tools v0.1.5 // indirect
 	gopkg.in/src-d/go-git.v4 v4.13.1
 	gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
 	helm.sh/helm/v3 v3.4.0
diff --git a/go.sum b/go.sum
index aa1a9ec1b..3853c6422 100644
--- a/go.sum
+++ b/go.sum
@@ -124,6 +124,16 @@ github.com/Azure/go-ntlmssp v0.0.0-20180810175552-4a21cbd618b4/go.mod h1:chxPXzS
 github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
 github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/BurntSushi/toml v0.3.2-0.20210614224209-34d990aa228d/go.mod h1:2QZjSXA5e+XyFeCAxxtL8Z4StYUsTquL8ODGPR3C3MA=
+github.com/BurntSushi/toml v0.3.2-0.20210621044154-20a94d639b8e/go.mod h1:t4zg8TkHfP16Vb3x4WKIw7zVYMit5QFtPEO8lOWxzTg=
+github.com/BurntSushi/toml v0.3.2-0.20210624061728-01bfc69d1057/go.mod h1:NMj2lD5LfMqcE0w8tnqOsH6944oaqpI1974lrIwerfE=
+github.com/BurntSushi/toml v0.3.2-0.20210704081116-ccff24ee4463/go.mod h1:EkRrMiQQmfxK6kIldz3QbPlhmVkrjW1RDJUnbDqGYvc=
+github.com/BurntSushi/toml v0.4.0 h1:qD/r9AL67srjW6O3fcSKZDsXqzBNX6ieSRywr2hRrdE=
+github.com/BurntSushi/toml v0.4.0/go.mod h1:wtejDu7Q0FhCWAo2aXkywSJyYFg01EDTKozLNCz2JBA=
+github.com/BurntSushi/toml-test v0.1.1-0.20210620192437-de01089bbf76/go.mod h1:P/PrhmZ37t5llHfDuiouWXtFgqOoQ12SAh9j6EjrBR4=
+github.com/BurntSushi/toml-test v0.1.1-0.20210624055653-1f6389604dc6/go.mod h1:UAIt+Eo8itMZAAgImXkPGDMYsT1SsJkVdB5TuONl86A=
+github.com/BurntSushi/toml-test v0.1.1-0.20210704062846-269931e74e3f/go.mod h1:fnFWrIwqgHsEjVsW3RYCJmDo86oq9eiJ9u6bnqhtm2g=
+github.com/BurntSushi/toml-test v0.1.1-0.20210723065233-facb9eccd4da/go.mod h1:ve9Q/RRu2vHi42LocPLNvagxuUJh993/95b18bw/Nws=
 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
 github.com/ChrisTrenkamp/goxpath v0.0.0-20170922090931-c385f95c6022/go.mod h1:nuWgzSkT5PnyOd+272uUmV0dnAnAn42Mk7PiQC5VzN4=
 github.com/ChrisTrenkamp/goxpath v0.0.0-20190607011252-c5096ec8773d/go.mod h1:nuWgzSkT5PnyOd+272uUmV0dnAnAn42Mk7PiQC5VzN4=
@@ -1805,6 +1815,8 @@ golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4f
 golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
 golang.org/x/tools v0.1.4 h1:cVngSRcfgyZCzys3KYOpCFa+4dqX/Oub9tAq00ttGVs=
 golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
+golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA=
+golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -2095,3 +2107,4 @@ sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1
 sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0=
 sourcegraph.com/sqs/pbtypes v1.0.0/go.mod h1:3AciMUv4qUuRHRHhOG4TZOB+72GdPVz5k+c648qsFS4=
 vbom.ml/util v0.0.0-20160121211510-db5cfe13f5cc/go.mod h1:so/NYdZXCz+E3ZpW0uAoCj6uzU2+8OWDFv/HxUSs7kI=
+zgo.at/zli v0.0.0-20210619044753-e7020a328e59/go.mod h1:HLAc12TjNGT+VRXr76JnsNE3pbooQtwKWhX+RlDjQ2Y=
diff --git a/pkg/cli/run.go b/pkg/cli/run.go
index 25139115f..676c9f1f2 100644
--- a/pkg/cli/run.go
+++ b/pkg/cli/run.go
@@ -88,7 +88,7 @@ type ScanOptions struct {
 	// severity is the level of severity of policy violations that should be reported
 	severity string
 
-	// verbose indicates whether to display all fields in default human readlbe output
+	// verbose indicates whether to display all fields in default human readable output
 	verbose bool
 
 	// showPassedRules indicates whether to display passed rules or not
@@ -96,6 +96,9 @@ type ScanOptions struct {
 
 	// nonRecursive enables recursive scan for the terraform iac provider
 	nonRecursive bool
+
+	// useTerraformCache provides ability to use terraform init local cache for modules rather than downloading them.
+	useTerraformCache bool
 }
 
 // NewScanOptions returns a new pointer to ScanOptions
@@ -181,7 +184,7 @@ func (s *ScanOptions) Run() error {
 
 	// create a new runtime executor for processing IaC
 	executor, err := runtime.NewExecutor(s.iacType, s.iacVersion, s.policyType,
-		s.iacFilePath, s.iacDirPath, s.policyPath, s.scanRules, s.skipRules, s.categories, s.severity, s.nonRecursive)
+		s.iacFilePath, s.iacDirPath, s.policyPath, s.scanRules, s.skipRules, s.categories, s.severity, s.nonRecursive, s.useTerraformCache)
 	if err != nil {
 		return err
 	}
diff --git a/pkg/cli/scan.go b/pkg/cli/scan.go
index a367312de..38a55f006 100644
--- a/pkg/cli/scan.go
+++ b/pkg/cli/scan.go
@@ -72,5 +72,6 @@ func init() {
 	scanCmd.Flags().StringSliceVarP(&scanOptions.categories, "categories", "", []string{}, "list of categories of violations to be reported by terrascan (example: --categories=\"category1,category2\")")
 	scanCmd.Flags().BoolVarP(&scanOptions.showPassedRules, "show-passed", "", false, "display passed rules, along with violations")
 	scanCmd.Flags().BoolVarP(&scanOptions.nonRecursive, "non-recursive", "", false, "do not scan directories and modules recursively")
+	scanCmd.Flags().BoolVarP(&scanOptions.useTerraformCache, "use-terraform-cache", "", false, "use terraform init cache for remote modules (when used directory scan will be non recursive, flag applicable only with terraform IaC provider)")
 	RegisterCommand(rootCmd, scanCmd)
 }
diff --git a/pkg/http-server/file-scan.go b/pkg/http-server/file-scan.go
index 92b4218fb..d44bfc420 100644
--- a/pkg/http-server/file-scan.go
+++ b/pkg/http-server/file-scan.go
@@ -152,10 +152,10 @@ func (g *APIHandler) scanFile(w http.ResponseWriter, r *http.Request) {
 	var executor *runtime.Executor
 	if g.test {
 		executor, err = runtime.NewExecutor(iacType, iacVersion, cloudType,
-			tempFile.Name(), "", []string{"./testdata/testpolicies"}, scanRules, skipRules, categories, severity, false)
+			tempFile.Name(), "", []string{"./testdata/testpolicies"}, scanRules, skipRules, categories, severity, false, false)
 	} else {
 		executor, err = runtime.NewExecutor(iacType, iacVersion, cloudType,
-			tempFile.Name(), "", getPolicyPathFromConfig(), scanRules, skipRules, categories, severity, false)
+			tempFile.Name(), "", getPolicyPathFromConfig(), scanRules, skipRules, categories, severity, false, false)
 	}
 	if err != nil {
 		zap.S().Error(err)
diff --git a/pkg/http-server/remote-repo.go b/pkg/http-server/remote-repo.go
index 67786b6c8..1909158e0 100644
--- a/pkg/http-server/remote-repo.go
+++ b/pkg/http-server/remote-repo.go
@@ -128,7 +128,7 @@ func (s *scanRemoteRepoReq) ScanRemoteRepo(iacType, iacVersion string, cloudType
 
 	// create a new runtime executor for scanning the remote repo
 	executor, err := runtime.NewExecutor(iacType, iacVersion, cloudType,
-		"", iacDirPath, policyPath, s.ScanRules, s.SkipRules, s.Categories, s.Severity, s.NonRecursive)
+		"", iacDirPath, policyPath, s.ScanRules, s.SkipRules, s.Categories, s.Severity, s.NonRecursive, false)
 	if err != nil {
 		zap.S().Error(err)
 		return output, isAdmissionDenied, err
diff --git a/pkg/iac-providers/arm/v1/load-dir.go b/pkg/iac-providers/arm/v1/load-dir.go
index bb4b34918..947bec047 100644
--- a/pkg/iac-providers/arm/v1/load-dir.go
+++ b/pkg/iac-providers/arm/v1/load-dir.go
@@ -35,7 +35,7 @@ import (
 const iacFile = "IAC file"
 
 // LoadIacDir loads all ARM template files in the current directory.
-func (a *ARMV1) LoadIacDir(absRootDir string, nonRecursive bool) (output.AllResourceConfigs, error) {
+func (a *ARMV1) LoadIacDir(absRootDir string, options map[string]interface{}) (output.AllResourceConfigs, error) {
 	// set the root directory being scanned
 	a.absRootDir = absRootDir
 
@@ -62,7 +62,7 @@ func (a *ARMV1) LoadIacDir(absRootDir string, nonRecursive bool) (output.AllReso
 			a.tryGetParameters(*files[i], fileDir, files)
 
 			var configData output.AllResourceConfigs
-			if configData, err = a.LoadIacFile(file); err != nil {
+			if configData, err = a.LoadIacFile(file, options); err != nil {
 				errMsg := fmt.Sprintf("error while loading iac file '%s'. err: %v", file, err)
 				zap.S().Debug("error while loading iac files", zap.String("IAC file", file), zap.Error(err))
 				a.errIacLoadDirs = multierror.Append(a.errIacLoadDirs, results.DirScanErr{IacType: "arm", Directory: fileDir, ErrMessage: errMsg})
diff --git a/pkg/iac-providers/arm/v1/load-file.go b/pkg/iac-providers/arm/v1/load-file.go
index d044eb8f5..83b633256 100644
--- a/pkg/iac-providers/arm/v1/load-file.go
+++ b/pkg/iac-providers/arm/v1/load-file.go
@@ -34,7 +34,7 @@ import (
 
 // LoadIacFile loads the specified ARM template file.
 // Note that a single ARM template json file may contain multiple resource definitions.
-func (a *ARMV1) LoadIacFile(absFilePath string) (allResourcesConfig output.AllResourceConfigs, err error) {
+func (a *ARMV1) LoadIacFile(absFilePath string, options map[string]interface{}) (allResourcesConfig output.AllResourceConfigs, err error) {
 	allResourcesConfig = make(output.AllResourceConfigs)
 	if fileExt := a.getFileType(absFilePath); fileExt != JSONExtension {
 		return allResourcesConfig, fmt.Errorf("unsupported file %s", absFilePath)
diff --git a/pkg/iac-providers/cft/v1/load-dir.go b/pkg/iac-providers/cft/v1/load-dir.go
index 8cca2d2bc..6d440a65c 100644
--- a/pkg/iac-providers/cft/v1/load-dir.go
+++ b/pkg/iac-providers/cft/v1/load-dir.go
@@ -29,7 +29,7 @@ import (
 )
 
 // LoadIacDir loads all CFT template files in the current directory.
-func (a *CFTV1) LoadIacDir(absRootDir string, nonRecursive bool) (output.AllResourceConfigs, error) {
+func (a *CFTV1) LoadIacDir(absRootDir string, options map[string]interface{}) (output.AllResourceConfigs, error) {
 	a.absRootDir = absRootDir
 
 	allResourcesConfig := make(map[string][]output.ResourceConfig)
@@ -45,7 +45,7 @@ func (a *CFTV1) LoadIacDir(absRootDir string, nonRecursive bool) (output.AllReso
 			file := filepath.Join(fileDir, *files[i])
 
 			var configData output.AllResourceConfigs
-			if configData, err = a.LoadIacFile(file); err != nil {
+			if configData, err = a.LoadIacFile(file, options); err != nil {
 				errMsg := fmt.Sprintf("error while loading iac file '%s', err: %v", file, err)
 				zap.S().Debug("error while loading iac files", zap.String("IAC file", file), zap.Error(err))
 				a.errIacLoadDirs = multierror.Append(a.errIacLoadDirs, results.DirScanErr{IacType: "cft", Directory: fileDir, ErrMessage: errMsg})
diff --git a/pkg/iac-providers/cft/v1/load-file.go b/pkg/iac-providers/cft/v1/load-file.go
index 322599a2f..4700968a0 100644
--- a/pkg/iac-providers/cft/v1/load-file.go
+++ b/pkg/iac-providers/cft/v1/load-file.go
@@ -32,7 +32,7 @@ import (
 
 // LoadIacFile loads the specified CFT template file.
 // Note that a single CFT template json file may contain multiple resource definitions.
-func (a *CFTV1) LoadIacFile(absFilePath string) (allResourcesConfig output.AllResourceConfigs, err error) {
+func (a *CFTV1) LoadIacFile(absFilePath string, options map[string]interface{}) (allResourcesConfig output.AllResourceConfigs, err error) {
 	fileData, err := ioutil.ReadFile(absFilePath)
 	if err != nil {
 		zap.S().Debug("unable to read file", zap.Error(err), zap.String("file", absFilePath))
diff --git a/pkg/iac-providers/docker/v1/load-dir.go b/pkg/iac-providers/docker/v1/load-dir.go
index f4b9aa073..c6d89736c 100644
--- a/pkg/iac-providers/docker/v1/load-dir.go
+++ b/pkg/iac-providers/docker/v1/load-dir.go
@@ -28,7 +28,7 @@ import (
 )
 
 // LoadIacDir loads the docker file specified in given folder.
-func (dc *DockerV1) LoadIacDir(absRootDir string, nonRecursive bool) (output.AllResourceConfigs, error) {
+func (dc *DockerV1) LoadIacDir(absRootDir string, options map[string]interface{}) (output.AllResourceConfigs, error) {
 	// set the root directory being scanned
 	dc.absRootDir = absRootDir
 
@@ -49,7 +49,7 @@ func (dc *DockerV1) LoadIacDir(absRootDir string, nonRecursive bool) (output.All
 		for i := range files {
 			file := filepath.Join(fileDir, *files[i])
 			var configData output.AllResourceConfigs
-			if configData, err = dc.LoadIacFile(file); err != nil {
+			if configData, err = dc.LoadIacFile(file, options); err != nil {
 				errMsg := fmt.Sprintf("error while parsing file %s", file)
 				zap.S().Errorf("error while searching for iac files", zap.String("root dir", absRootDir), errMsg)
 				dc.errIacLoadDirs = multierror.Append(dc.errIacLoadDirs, results.DirScanErr{IacType: "docker", Directory: absRootDir, ErrMessage: errMsg})
diff --git a/pkg/iac-providers/docker/v1/load-file.go b/pkg/iac-providers/docker/v1/load-file.go
index 0eab0e6d9..9f6c4425f 100644
--- a/pkg/iac-providers/docker/v1/load-file.go
+++ b/pkg/iac-providers/docker/v1/load-file.go
@@ -41,7 +41,7 @@ const (
 )
 
 // LoadIacFile loads the docker file specified and create ResourceConfig for each dockerfile
-func (dc *DockerV1) LoadIacFile(absFilePath string) (allResourcesConfig output.AllResourceConfigs, err error) {
+func (dc *DockerV1) LoadIacFile(absFilePath string, options map[string]interface{}) (allResourcesConfig output.AllResourceConfigs, err error) {
 	allResourcesConfig = make(map[string][]output.ResourceConfig)
 
 	data, comments, err := dc.Parse(absFilePath)
diff --git a/pkg/iac-providers/helm/v3/load-dir.go b/pkg/iac-providers/helm/v3/load-dir.go
index 1850c2bf3..598344c3b 100644
--- a/pkg/iac-providers/helm/v3/load-dir.go
+++ b/pkg/iac-providers/helm/v3/load-dir.go
@@ -42,7 +42,7 @@ var (
 )
 
 // LoadIacDir loads all helm charts under the specified directory
-func (h *HelmV3) LoadIacDir(absRootDir string, nonRecursive bool) (output.AllResourceConfigs, error) {
+func (h *HelmV3) LoadIacDir(absRootDir string, options map[string]interface{}) (output.AllResourceConfigs, error) {
 
 	allResourcesConfig := make(map[string][]output.ResourceConfig)
 
diff --git a/pkg/iac-providers/helm/v3/load-file.go b/pkg/iac-providers/helm/v3/load-file.go
index 71064925c..4258a6205 100644
--- a/pkg/iac-providers/helm/v3/load-file.go
+++ b/pkg/iac-providers/helm/v3/load-file.go
@@ -28,7 +28,7 @@ var (
 )
 
 // LoadIacFile is not supported for helm. Only loading chart directories are supported
-func (h *HelmV3) LoadIacFile(absRootPath string) (allResourcesConfig output.AllResourceConfigs, err error) {
+func (h *HelmV3) LoadIacFile(absRootPath string, options map[string]interface{}) (allResourcesConfig output.AllResourceConfigs, err error) {
 	zap.S().Errorf("load iac file is not supported for helm")
 	return make(map[string][]output.ResourceConfig), errLoadIacFileNotSupported
 }
diff --git a/pkg/iac-providers/interface.go b/pkg/iac-providers/interface.go
index a962c8ea3..3d94118ab 100644
--- a/pkg/iac-providers/interface.go
+++ b/pkg/iac-providers/interface.go
@@ -23,6 +23,6 @@ import (
 // IacProvider defines the interface which every IaC provider needs to implement
 // to claim support in terrascan
 type IacProvider interface {
-	LoadIacFile(string) (output.AllResourceConfigs, error)
-	LoadIacDir(string, bool) (output.AllResourceConfigs, error)
+	LoadIacFile(string, map[string]interface{}) (output.AllResourceConfigs, error)
+	LoadIacDir(string, map[string]interface{}) (output.AllResourceConfigs, error)
 }
diff --git a/pkg/iac-providers/kubernetes/v1/load-dir.go b/pkg/iac-providers/kubernetes/v1/load-dir.go
index a606420bd..faeeb85a6 100644
--- a/pkg/iac-providers/kubernetes/v1/load-dir.go
+++ b/pkg/iac-providers/kubernetes/v1/load-dir.go
@@ -25,7 +25,7 @@ func (*K8sV1) getFileType(file string) string {
 }
 
 // LoadIacDir loads all k8s files in the current directory
-func (k *K8sV1) LoadIacDir(absRootDir string, nonRecursive bool) (output.AllResourceConfigs, error) {
+func (k *K8sV1) LoadIacDir(absRootDir string, options map[string]interface{}) (output.AllResourceConfigs, error) {
 	// set the root directory being scanned
 	k.absRootDir = absRootDir
 
@@ -42,7 +42,7 @@ func (k *K8sV1) LoadIacDir(absRootDir string, nonRecursive bool) (output.AllReso
 			file := filepath.Join(fileDir, *files[i])
 
 			var configData output.AllResourceConfigs
-			if configData, err = k.LoadIacFile(file); err != nil {
+			if configData, err = k.LoadIacFile(file, options); err != nil {
 				errMsg := fmt.Sprintf("error while loading iac file '%s'. err: %v", file, err)
 				zap.S().Debug("error while loading iac files", zap.String("IAC file", file), zap.Error(err))
 				k.errIacLoadDirs = multierror.Append(k.errIacLoadDirs, results.DirScanErr{IacType: "k8s", Directory: fileDir, ErrMessage: errMsg})
diff --git a/pkg/iac-providers/kubernetes/v1/load-file.go b/pkg/iac-providers/kubernetes/v1/load-file.go
index dccb13b02..a672d1c5d 100644
--- a/pkg/iac-providers/kubernetes/v1/load-file.go
+++ b/pkg/iac-providers/kubernetes/v1/load-file.go
@@ -12,7 +12,7 @@ import (
 
 // LoadIacFile loads the k8s file specified
 // Note that a single k8s yaml file may contain multiple resource definitions
-func (k *K8sV1) LoadIacFile(absFilePath string) (allResourcesConfig output.AllResourceConfigs, err error) {
+func (k *K8sV1) LoadIacFile(absFilePath string, options map[string]interface{}) (allResourcesConfig output.AllResourceConfigs, err error) {
 	allResourcesConfig = make(map[string][]output.ResourceConfig)
 
 	var iacDocuments []*utils.IacDocument
diff --git a/pkg/iac-providers/kustomize/v3/load-dir.go b/pkg/iac-providers/kustomize/v3/load-dir.go
index fd7e179cd..5963b3a02 100644
--- a/pkg/iac-providers/kustomize/v3/load-dir.go
+++ b/pkg/iac-providers/kustomize/v3/load-dir.go
@@ -23,7 +23,7 @@ var (
 )
 
 // LoadIacDir loads the kustomize directory and returns the ResourceConfig mapping which is evaluated by the policy engine
-func (k *KustomizeV3) LoadIacDir(absRootDir string, nonRecursive bool) (output.AllResourceConfigs, error) {
+func (k *KustomizeV3) LoadIacDir(absRootDir string, options map[string]interface{}) (output.AllResourceConfigs, error) {
 
 	allResourcesConfig := make(map[string][]output.ResourceConfig)
 
diff --git a/pkg/iac-providers/kustomize/v3/load-file.go b/pkg/iac-providers/kustomize/v3/load-file.go
index 41dc186de..02967d5c0 100644
--- a/pkg/iac-providers/kustomize/v3/load-file.go
+++ b/pkg/iac-providers/kustomize/v3/load-file.go
@@ -12,7 +12,7 @@ var (
 )
 
 // LoadIacFile is not supported for kustomize. Only loading directories that have kustomization.y(a)ml file are supported
-func (k *KustomizeV3) LoadIacFile(absRootPath string) (allResourcesConfig output.AllResourceConfigs, err error) {
+func (k *KustomizeV3) LoadIacFile(absRootPath string, options map[string]interface{}) (allResourcesConfig output.AllResourceConfigs, err error) {
 	zap.S().Error(errLoadIacFileNotSupported)
 	return make(map[string][]output.ResourceConfig), errLoadIacFileNotSupported
 }
diff --git a/pkg/iac-providers/terraform/commons/load-dir.go b/pkg/iac-providers/terraform/commons/load-dir.go
index a513ca8e1..624a25810 100644
--- a/pkg/iac-providers/terraform/commons/load-dir.go
+++ b/pkg/iac-providers/terraform/commons/load-dir.go
@@ -17,10 +17,13 @@
 package commons
 
 import (
+	"encoding/json"
 	"errors"
 	"fmt"
+	"io/ioutil"
 	"os"
 	"path/filepath"
+	"strings"
 
 	"github.com/accurics/terrascan/pkg/downloader"
 	"github.com/accurics/terrascan/pkg/iac-providers/output"
@@ -40,6 +43,24 @@ var (
 	ErrBuildTFConfigDir = fmt.Errorf("failed to build terraform allResourcesConfig")
 )
 
+const (
+	terraformModuleInstallDir             = ".terraform/modules"
+	terraformInstalledModulelMetaFileName = "modules.json"
+)
+
+// TerraformInstalledModuleMetaData metadata about the module downloaded and present in terraform cache.
+type TerraformInstalledModuleMetaData struct {
+	Key        string `json:"Key"`
+	SourceAddr string `json:"Source"`
+	VersionStr string `json:"Version,omitempty"`
+	Dir        string `json:"Dir"`
+}
+
+//TerraformModuleManifest holds details of all modules downloaded by terraform
+type TerraformModuleManifest struct {
+	Modules []TerraformInstalledModuleMetaData `json:"Modules"`
+}
+
 // ModuleConfig contains the *hclConfigs.Config for every module in the
 // unified config tree along with *hclConfig.ModuleCall made by the parent
 // module. The ParentModuleCall helps in resolving references for variables
@@ -52,21 +73,33 @@ type ModuleConfig struct {
 
 // TerraformDirectoryLoader implements terraform directory loading
 type TerraformDirectoryLoader struct {
-	absRootDir       string
-	nonRecursive     bool
-	remoteDownloader downloader.ModuleDownloader
-	parser           *hclConfigs.Parser
-	errIacLoadDirs   *multierror.Error
+	absRootDir               string
+	nonRecursive             bool
+	useTerraformCache        bool
+	remoteDownloader         downloader.ModuleDownloader
+	parser                   *hclConfigs.Parser
+	errIacLoadDirs           *multierror.Error
+	terraformInitModuleCache map[string]TerraformModuleManifest
 }
 
 // NewTerraformDirectoryLoader creates a new terraformDirectoryLoader
-func NewTerraformDirectoryLoader(rootDirectory string, nonRecursive bool) TerraformDirectoryLoader {
-	return TerraformDirectoryLoader{
-		absRootDir:       rootDirectory,
-		nonRecursive:     nonRecursive,
-		remoteDownloader: downloader.NewRemoteDownloader(),
-		parser:           hclConfigs.NewParser(afero.NewOsFs()),
+func NewTerraformDirectoryLoader(rootDirectory string, options map[string]interface{}) TerraformDirectoryLoader {
+	terraformDirectoryLoader := TerraformDirectoryLoader{
+		absRootDir:               rootDirectory,
+		remoteDownloader:         downloader.NewRemoteDownloader(),
+		parser:                   hclConfigs.NewParser(afero.NewOsFs()),
+		terraformInitModuleCache: make(map[string]TerraformModuleManifest),
+	}
+	for key, val := range options {
+		// keeping switch case in case more flags are added
+		switch key {
+		case "useTerraformCache":
+			terraformDirectoryLoader.useTerraformCache = val.(bool)
+		case "nonRecursive":
+			terraformDirectoryLoader.nonRecursive = val.(bool)
+		}
 	}
+	return terraformDirectoryLoader
 }
 
 // LoadIacDir starts traversing from the given rootDir and traverses through
@@ -76,7 +109,7 @@ func (t TerraformDirectoryLoader) LoadIacDir() (allResourcesConfig output.AllRes
 
 	defer t.remoteDownloader.CleanUp()
 
-	if t.nonRecursive {
+	if t.nonRecursive || t.useTerraformCache {
 		return t.loadDirNonRecursive()
 	}
 
@@ -335,22 +368,30 @@ func (t TerraformDirectoryLoader) buildUnifiedConfig(rootMod *hclConfigs.Module,
 
 				pathToModule = t.processLocalSource(req)
 				zap.S().Debugf("processing local module %q", pathToModule)
-			} else if downloader.IsRegistrySourceAddr(req.SourceAddr) {
-				// temp dir to download the remote repo
-				tempDir := utils.GenerateTempDir()
-
-				pathToModule, err = t.processTerraformRegistrySource(req, tempDir)
-				if err != nil {
-					zap.S().Errorf("failed to download remote module %q. error: '%v'", req.SourceAddr, err)
+			} else if t.useTerraformCache {
+				// check if module is present in terraform cache
+				if _, dest := t.GetRemoteModuleIfPresentInTerraformSrc(req); dest != "" {
+					pathToModule = dest
 				}
-			} else {
-				// temp dir to download the remote repo
-				tempDir := utils.GenerateTempDir()
+			}
+			if pathToModule == "" {
+				if downloader.IsRegistrySourceAddr(req.SourceAddr) {
+					// temp dir to download the remote repo
+					tempDir := utils.GenerateTempDir()
+
+					pathToModule, err = t.processTerraformRegistrySource(req, tempDir)
+					if err != nil {
+						zap.S().Errorf("failed to download remote module %q. error: '%v'", req.SourceAddr, err)
+					}
+				} else {
+					// temp dir to download the remote repo
+					tempDir := utils.GenerateTempDir()
 
-				// Download remote module
-				pathToModule, err = t.remoteDownloader.DownloadModule(req.SourceAddr, tempDir)
-				if err != nil {
-					zap.S().Errorf("failed to download remote module %q. error: '%v'", req.SourceAddr, err)
+					// Download remote module
+					pathToModule, err = t.remoteDownloader.DownloadModule(req.SourceAddr, tempDir)
+					if err != nil {
+						zap.S().Errorf("failed to download remote module %q. error: '%v'", req.SourceAddr, err)
+					}
 				}
 			}
 
@@ -459,3 +500,63 @@ func GetConfigSource(remoteURLMapping map[string]string, resourceConfig output.R
 	}
 	return source, nil
 }
+
+// GetRemoteModuleIfPresentInTerraformSrc - Gets the remote module if present in terraform init cache
+func (t *TerraformDirectoryLoader) GetRemoteModuleIfPresentInTerraformSrc(req *hclConfigs.ModuleRequest) (src string, destpath string) {
+	terraformInitRegs := filepath.Join(t.absRootDir, terraformModuleInstallDir)
+	modules := TerraformModuleManifest{}
+	var ok bool
+	if modules, ok = t.terraformInitModuleCache[terraformInitRegs]; !ok {
+		if utils.IsDirExists(terraformInitRegs) {
+			_, err := os.Stat(filepath.Join(terraformInitRegs, terraformInstalledModulelMetaFileName))
+			if err != nil {
+				if os.IsNotExist(err) {
+					zap.S().Debug("found no terraform module metadata file in dir %s", terraformInitRegs)
+					return
+				}
+				zap.S().Error("error reading terraform module metadata file", err)
+				return
+			}
+			data, err := ioutil.ReadFile(filepath.Join(terraformInitRegs, terraformInstalledModulelMetaFileName))
+			if err == nil {
+				err := json.Unmarshal(data, &modules)
+				if err != nil {
+					zap.S().Error("error unmarshalling terraform module metadata", err)
+					return
+				}
+			}
+		}
+		// if the module metadata file was read first time add that to cache against the found working directory
+		t.terraformInitModuleCache[terraformInitRegs] = modules
+	}
+	for _, m := range modules.Modules {
+		if strings.EqualFold(m.SourceAddr, req.SourceAddr) {
+			// if the module source is not registry then version check is not required
+			if !downloader.IsRegistrySourceAddr(req.SourceAddr) {
+				return req.SourceAddr, filepath.Join(t.absRootDir, m.Dir)
+			} else if versionSatisfied(m.VersionStr, req.VersionConstraint) {
+				return req.SourceAddr, filepath.Join(t.absRootDir, m.Dir)
+			}
+		}
+	}
+	zap.S().Debug("found no version matching for module: %s in terraform module cache %s", req.Name, filepath.Join(terraformInitRegs, "modules.json"))
+	return
+}
+
+//versionSatisfied - check version in terraform init cache satisfies the required version constraints
+func versionSatisfied(foundversion string, requiredVersion hclConfigs.VersionConstraint) bool {
+	currentVersion, err := version.NewVersion(foundversion)
+	if err != nil {
+		return false
+	}
+
+	if requiredVersion.Required == nil && foundversion != "" {
+		return true
+	}
+
+	if requiredVersion.Required.Check(currentVersion) {
+		return true
+	}
+
+	return false
+}
diff --git a/pkg/iac-providers/terraform/v12/load-dir.go b/pkg/iac-providers/terraform/v12/load-dir.go
index 471a08465..6675e82bf 100644
--- a/pkg/iac-providers/terraform/v12/load-dir.go
+++ b/pkg/iac-providers/terraform/v12/load-dir.go
@@ -25,7 +25,7 @@ import (
 // LoadIacDir starts traversing from the given rootDir and traverses through
 // all the descendant modules present to create an output list of all the
 // resources present in rootDir and descendant modules
-func (*TfV12) LoadIacDir(absRootDir string, nonRecursive bool) (allResourcesConfig output.AllResourceConfigs, err error) {
+func (*TfV12) LoadIacDir(absRootDir string, options map[string]interface{}) (allResourcesConfig output.AllResourceConfigs, err error) {
 	zap.S().Warn("There may be a few breaking changes while working with terraform v0.12 files. For further information, refer to https://github.com/accurics/terrascan/releases/v1.3.0")
-	return commons.NewTerraformDirectoryLoader(absRootDir, nonRecursive).LoadIacDir()
+	return commons.NewTerraformDirectoryLoader(absRootDir, options).LoadIacDir()
 }
diff --git a/pkg/iac-providers/terraform/v12/load-file.go b/pkg/iac-providers/terraform/v12/load-file.go
index c55f4d0db..a94e16de2 100644
--- a/pkg/iac-providers/terraform/v12/load-file.go
+++ b/pkg/iac-providers/terraform/v12/load-file.go
@@ -23,7 +23,7 @@ import (
 )
 
 // LoadIacFile parses the given terraform file from the given file path
-func (*TfV12) LoadIacFile(absFilePath string) (allResourcesConfig output.AllResourceConfigs, err error) {
+func (*TfV12) LoadIacFile(absFilePath string, options map[string]interface{}) (allResourcesConfig output.AllResourceConfigs, err error) {
 	zap.S().Warn("There may be a few breaking changes while working with terraform v0.12 files. For further information, refer to https://github.com/accurics/terrascan/releases/v1.3.0")
 	return commons.LoadIacFile(absFilePath)
 }
diff --git a/pkg/iac-providers/terraform/v14/load-dir.go b/pkg/iac-providers/terraform/v14/load-dir.go
index 9dac6d8ef..3790d0294 100644
--- a/pkg/iac-providers/terraform/v14/load-dir.go
+++ b/pkg/iac-providers/terraform/v14/load-dir.go
@@ -25,6 +25,6 @@ import (
 // LoadIacDir starts traversing from the given rootDir and traverses through
 // all the descendant modules present to create an output list of all the
 // resources present in rootDir and descendant modules
-func (*TfV14) LoadIacDir(absRootDir string, nonRecursive bool) (allResourcesConfig output.AllResourceConfigs, err error) {
-	return commons.NewTerraformDirectoryLoader(absRootDir, nonRecursive).LoadIacDir()
+func (tfv14 *TfV14) LoadIacDir(absRootDir string, options map[string]interface{}) (allResourcesConfig output.AllResourceConfigs, err error) {
+	return commons.NewTerraformDirectoryLoader(absRootDir, options).LoadIacDir()
 }
diff --git a/pkg/iac-providers/terraform/v14/load-file.go b/pkg/iac-providers/terraform/v14/load-file.go
index 43d61043a..a24293960 100644
--- a/pkg/iac-providers/terraform/v14/load-file.go
+++ b/pkg/iac-providers/terraform/v14/load-file.go
@@ -22,6 +22,6 @@ import (
 )
 
 // LoadIacFile parses the given terraform file from the given file path
-func (*TfV14) LoadIacFile(absFilePath string) (allResourcesConfig output.AllResourceConfigs, err error) {
+func (*TfV14) LoadIacFile(absFilePath string, options map[string]interface{}) (allResourcesConfig output.AllResourceConfigs, err error) {
 	return commons.LoadIacFile(absFilePath)
 }
diff --git a/pkg/iac-providers/terraform/v15/load-dir.go b/pkg/iac-providers/terraform/v15/load-dir.go
index 3049f4b73..759e144ca 100644
--- a/pkg/iac-providers/terraform/v15/load-dir.go
+++ b/pkg/iac-providers/terraform/v15/load-dir.go
@@ -25,6 +25,7 @@ import (
 // LoadIacDir starts traversing from the given rootDir and traverses through
 // all the descendant modules present to create an output list of all the
 // resources present in rootDir and descendant modules
-func (*TfV15) LoadIacDir(absRootDir string, nonRecursive bool) (allResourcesConfig output.AllResourceConfigs, err error) {
-	return commons.NewTerraformDirectoryLoader(absRootDir, nonRecursive).LoadIacDir()
+func (*TfV15) LoadIacDir(absRootDir string, options map[string]interface{}) (allResourcesConfig output.AllResourceConfigs, err error) {
+
+	return commons.NewTerraformDirectoryLoader(absRootDir, options).LoadIacDir()
 }
diff --git a/pkg/iac-providers/terraform/v15/load-file.go b/pkg/iac-providers/terraform/v15/load-file.go
index f2ef8588a..345faebc8 100644
--- a/pkg/iac-providers/terraform/v15/load-file.go
+++ b/pkg/iac-providers/terraform/v15/load-file.go
@@ -22,6 +22,6 @@ import (
 )
 
 // LoadIacFile parses the given terraform file from the given file path
-func (*TfV15) LoadIacFile(absFilePath string) (allResourcesConfig output.AllResourceConfigs, err error) {
+func (*TfV15) LoadIacFile(absFilePath string, options map[string]interface{}) (allResourcesConfig output.AllResourceConfigs, err error) {
 	return commons.LoadIacFile(absFilePath)
 }
diff --git a/pkg/iac-providers/tfplan/v1/load-dir.go b/pkg/iac-providers/tfplan/v1/load-dir.go
index 2b7e070f2..aaf2cf3e5 100644
--- a/pkg/iac-providers/tfplan/v1/load-dir.go
+++ b/pkg/iac-providers/tfplan/v1/load-dir.go
@@ -28,6 +28,6 @@ var (
 
 // LoadIacDir is not supported for tfplan IacType. Terraform plan should always
 // be a file and not a directory
-func (k *TFPlan) LoadIacDir(absRootDir string, nonRecursive bool) (output.AllResourceConfigs, error) {
+func (k *TFPlan) LoadIacDir(absRootDir string, options map[string]interface{}) (output.AllResourceConfigs, error) {
 	return output.AllResourceConfigs{}, errIacDirNotSupport
 }
diff --git a/pkg/iac-providers/tfplan/v1/load-file.go b/pkg/iac-providers/tfplan/v1/load-file.go
index 9ceceabcf..004172633 100644
--- a/pkg/iac-providers/tfplan/v1/load-file.go
+++ b/pkg/iac-providers/tfplan/v1/load-file.go
@@ -37,7 +37,7 @@ var (
 )
 
 // LoadIacFile parses the given tfplan file from the given file path
-func (t *TFPlan) LoadIacFile(absFilePath string) (allResourcesConfig output.AllResourceConfigs, err error) {
+func (t *TFPlan) LoadIacFile(absFilePath string, options map[string]interface{}) (allResourcesConfig output.AllResourceConfigs, err error) {
 
 	zap.S().Debug("processing tfplan file")
 
diff --git a/pkg/k8s/admission-webhook/validating-webhook.go b/pkg/k8s/admission-webhook/validating-webhook.go
index c2aac25ee..eb69b03d7 100644
--- a/pkg/k8s/admission-webhook/validating-webhook.go
+++ b/pkg/k8s/admission-webhook/validating-webhook.go
@@ -191,10 +191,10 @@ func (w ValidatingWebhook) scanK8sFile(filePath string) (runtime.Output, error)
 
 	if flag.Lookup("test.v") != nil {
 		executor, err = runtime.NewExecutor("k8s", "v1", []string{"k8s"},
-			filePath, "", []string{testPoliciesPath}, []string{}, []string{}, []string{}, "", false)
+			filePath, "", []string{testPoliciesPath}, []string{}, []string{}, []string{}, "", false, false)
 	} else {
 		executor, err = runtime.NewExecutor("k8s", "v1", []string{"k8s"},
-			filePath, "", []string{}, []string{}, []string{}, []string{}, "", false)
+			filePath, "", []string{}, []string{}, []string{}, []string{}, "", false, false)
 	}
 	if err != nil {
 		zap.S().Errorf("failed to create runtime executer: '%v'", err)
diff --git a/pkg/policy/docker.go b/pkg/policy/docker.go
new file mode 100644
index 000000000..1ec3eb207
--- /dev/null
+++ b/pkg/policy/docker.go
@@ -0,0 +1,28 @@
+/*
+    Copyright (C) 2020 Accurics, Inc.
+
+	Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+		http://www.apache.org/licenses/LICENSE-2.0
+
+	Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+*/
+
+package policy
+
+const (
+	docker                  supportedCloudType  = "docker"
+	defaultDockerIacType    supportedIacType    = "docker"
+	defaultDockerIacVersion supportedIacVersion = version1
+)
+
+func init() {
+	// Register docker as a cloud provider with terrascan
+	RegisterCloudProvider(docker, defaultDockerIacType, defaultDockerIacVersion)
+}
diff --git a/pkg/runtime/executor.go b/pkg/runtime/executor.go
index a730316bf..e33a95381 100644
--- a/pkg/runtime/executor.go
+++ b/pkg/runtime/executor.go
@@ -17,9 +17,10 @@
 package runtime
 
 import (
-	"github.com/accurics/terrascan/pkg/policy/opa"
 	"sort"
 
+	"github.com/accurics/terrascan/pkg/policy/opa"
+
 	"go.uber.org/zap"
 
 	"github.com/accurics/terrascan/pkg/filters"
@@ -30,35 +31,42 @@ import (
 	"github.com/hashicorp/go-multierror"
 )
 
+const (
+	useTerraformCache = "useTerraformCache"
+	nonRecursive      = "nonRecursive"
+)
+
 // Executor object
 type Executor struct {
-	filePath      string
-	dirPath       string
-	policyPath    []string
-	iacType       string
-	iacVersion    string
-	scanRules     []string
-	skipRules     []string
-	iacProviders  []iacProvider.IacProvider
-	policyEngines []policy.Engine
-	notifiers     []notifications.Notifier
-	categories    []string
-	policyTypes   []string
-	severity      string
-	nonRecursive  bool
+	filePath          string
+	dirPath           string
+	policyPath        []string
+	iacType           string
+	iacVersion        string
+	scanRules         []string
+	skipRules         []string
+	iacProviders      []iacProvider.IacProvider
+	policyEngines     []policy.Engine
+	notifiers         []notifications.Notifier
+	categories        []string
+	policyTypes       []string
+	severity          string
+	nonRecursive      bool
+	useTerraformCache bool
 }
 
 // NewExecutor creates a runtime object
-func NewExecutor(iacType, iacVersion string, policyTypes []string, filePath, dirPath string, policyPath, scanRules, skipRules, categories []string, severity string, nonRecursive bool) (e *Executor, err error) {
+func NewExecutor(iacType, iacVersion string, policyTypes []string, filePath, dirPath string, policyPath, scanRules, skipRules, categories []string, severity string, nonRecursive, useTerraformCache bool) (e *Executor, err error) {
 	e = &Executor{
-		filePath:     filePath,
-		dirPath:      dirPath,
-		policyPath:   policyPath,
-		policyTypes:  policyTypes,
-		iacType:      iacType,
-		iacVersion:   iacVersion,
-		iacProviders: make([]iacProvider.IacProvider, 0),
-		nonRecursive: nonRecursive,
+		filePath:          filePath,
+		dirPath:           dirPath,
+		policyPath:        policyPath,
+		policyTypes:       policyTypes,
+		iacType:           iacType,
+		iacVersion:        iacVersion,
+		iacProviders:      make([]iacProvider.IacProvider, 0),
+		nonRecursive:      nonRecursive,
+		useTerraformCache: useTerraformCache,
 	}
 
 	// read config file and update scan and skip rules
@@ -159,6 +167,7 @@ func (e *Executor) initPolicyEngines() (err error) {
 		// initialize the engine
 		if err := engine.Init(policyPath, preloadFilter); err != nil {
 			zap.S().Errorf("failed to initialize policy engine for path %s, error: %s", policyPath, err)
+			zap.S().Error("perform 'terrascan init' command and then try running the scan command again")
 			return err
 		}
 		e.policyEngines = append(e.policyEngines, engine)
@@ -178,9 +187,10 @@ func (e *Executor) Execute(configOnly bool) (results Output, err error) {
 		// get all resource configs in the directory
 		resourceConfig, merr = e.getResourceConfigs()
 	} else {
+		options := e.buildOptions()
 		// create results output from Iac provider
 		// iac providers will contain one element
-		resourceConfig, err = e.iacProviders[0].LoadIacFile(e.filePath)
+		resourceConfig, err = e.iacProviders[0].LoadIacFile(e.filePath, options)
 		if err != nil {
 			return results, err
 		}
@@ -242,10 +252,11 @@ func (e *Executor) getResourceConfigs() (output.AllResourceConfigs, *multierror.
 	// channel for directory scan response
 	scanRespChan := make(chan dirScanResp)
 
+	options := e.buildOptions()
 	// create results output from Iac provider[s]
 	for _, iacP := range e.iacProviders {
 		go func(ip iacProvider.IacProvider) {
-			rc, err := ip.LoadIacDir(e.dirPath, e.nonRecursive)
+			rc, err := ip.LoadIacDir(e.dirPath, options)
 			scanRespChan <- dirScanResp{err, rc}
 		}(iacP)
 	}
@@ -313,3 +324,11 @@ func implementsSubFolderScan(iacType string, nonRecursive bool) bool {
 	}
 	return false
 }
+
+// buildOptions builds map of scan options from executors config
+func (e *Executor) buildOptions() map[string]interface{} {
+	options := make(map[string]interface{})
+	options[useTerraformCache] = e.useTerraformCache
+	options[nonRecursive] = e.nonRecursive
+	return options
+}


Test patch:
diff --git a/pkg/iac-providers/arm/v1/load-dir_test.go b/pkg/iac-providers/arm/v1/load-dir_test.go
index 6063dbb44..edb799533 100644
--- a/pkg/iac-providers/arm/v1/load-dir_test.go
+++ b/pkg/iac-providers/arm/v1/load-dir_test.go
@@ -71,6 +71,7 @@ func TestLoadIacDir(t *testing.T) {
 		armv1   ARMV1
 		name    string
 		dirPath string
+		options map[string]interface{}
 	}{
 		{
 			name:    "empty config",
@@ -94,7 +95,7 @@ func TestLoadIacDir(t *testing.T) {
 
 	for _, tt := range table {
 		t.Run(tt.name, func(t *testing.T) {
-			aRC, gotErr := tt.armv1.LoadIacDir(tt.dirPath, false)
+			aRC, gotErr := tt.armv1.LoadIacDir(tt.dirPath, tt.options)
 			me, ok := gotErr.(*multierror.Error)
 			if !ok {
 				t.Errorf("expected multierror.Error, got %T", gotErr)
@@ -127,6 +128,8 @@ func TestARMMapper(t *testing.T) {
 		t.Error(err)
 	}
 
+	options := make(map[string]interface{})
+
 	armv1 := ARMV1{}
 
 	// get output json to verify
@@ -143,7 +146,7 @@ func TestARMMapper(t *testing.T) {
 
 	t.Run(root, func(t *testing.T) {
 
-		allResourceConfigs, gotErr := armv1.LoadIacDir(root, false)
+		allResourceConfigs, gotErr := armv1.LoadIacDir(root, options)
 		_, ok := gotErr.(*multierror.Error)
 		if !ok {
 			t.Errorf("expected multierror.Error, got %T", gotErr)
diff --git a/pkg/iac-providers/arm/v1/load-file_test.go b/pkg/iac-providers/arm/v1/load-file_test.go
index 6ba5dd65f..e155bac48 100644
--- a/pkg/iac-providers/arm/v1/load-file_test.go
+++ b/pkg/iac-providers/arm/v1/load-file_test.go
@@ -31,6 +31,7 @@ func TestLoadIacFile(t *testing.T) {
 	table := []struct {
 		wantErr  error
 		want     output.AllResourceConfigs
+		options  map[string]interface{}
 		armv1    ARMV1
 		name     string
 		filePath string
@@ -58,7 +59,7 @@ func TestLoadIacFile(t *testing.T) {
 
 	for _, tt := range table {
 		t.Run(tt.name, func(t *testing.T) {
-			_, gotErr := tt.armv1.LoadIacFile(tt.filePath)
+			_, gotErr := tt.armv1.LoadIacFile(tt.filePath, tt.options)
 			if !reflect.DeepEqual(gotErr, tt.wantErr) {
 				t.Errorf("unexpected error; gotErr: '%v', wantErr: '%v'", gotErr, tt.wantErr)
 			} else if tt.typeOnly && (reflect.TypeOf(gotErr)) != reflect.TypeOf(tt.wantErr) {
@@ -72,6 +73,7 @@ func TestLinkedTemplateDownload(t *testing.T) {
 	table := []struct {
 		wantErr  error
 		want     output.AllResourceConfigs
+		options  map[string]interface{}
 		armv1    ARMV1
 		name     string
 		filePath string
@@ -113,7 +115,7 @@ func TestLinkedTemplateDownload(t *testing.T) {
 
 	for _, tt := range table {
 		t.Run(tt.name, func(t *testing.T) {
-			aRC, gotErr := tt.armv1.LoadIacFile(tt.filePath)
+			aRC, gotErr := tt.armv1.LoadIacFile(tt.filePath, tt.options)
 			if !reflect.DeepEqual(gotErr, tt.wantErr) {
 				t.Errorf("unexpected error; gotErr: '%v', wantErr: '%v'", gotErr, tt.wantErr)
 			} else if tt.typeOnly && (reflect.TypeOf(gotErr)) != reflect.TypeOf(tt.wantErr) {
diff --git a/pkg/iac-providers/cft/v1/load-dir_test.go b/pkg/iac-providers/cft/v1/load-dir_test.go
index 58a7eb733..f880355ff 100644
--- a/pkg/iac-providers/cft/v1/load-dir_test.go
+++ b/pkg/iac-providers/cft/v1/load-dir_test.go
@@ -64,6 +64,7 @@ func TestLoadIacDir(t *testing.T) {
 		cftv1   CFTV1
 		name    string
 		dirPath string
+		options map[string]interface{}
 	}{
 		{
 			name:    "empty config",
@@ -95,7 +96,7 @@ func TestLoadIacDir(t *testing.T) {
 
 	for _, tt := range table {
 		t.Run(tt.name, func(t *testing.T) {
-			_, gotErr := tt.cftv1.LoadIacDir(tt.dirPath, false)
+			_, gotErr := tt.cftv1.LoadIacDir(tt.dirPath, tt.options)
 			me, ok := gotErr.(*multierror.Error)
 			if !ok {
 				t.Errorf("expected multierror.Error, got %T", gotErr)
@@ -117,12 +118,12 @@ func TestCFTMapper(t *testing.T) {
 	if err != nil {
 		log.Fatal(err)
 	}
-
+	options := make(map[string]interface{})
 	cftv1 := CFTV1{}
 	for _, dir := range dirList {
 		resourceDir := filepath.Join(root, dir.Name())
 		t.Run(resourceDir, func(t *testing.T) {
-			allResourceConfigs, gotErr := cftv1.LoadIacDir(resourceDir, false)
+			allResourceConfigs, gotErr := cftv1.LoadIacDir(resourceDir, options)
 
 			// load expected output.json from test artifacts
 			var testArc output.AllResourceConfigs
diff --git a/pkg/iac-providers/cft/v1/load-file_test.go b/pkg/iac-providers/cft/v1/load-file_test.go
index 57e6033ad..2913e996d 100644
--- a/pkg/iac-providers/cft/v1/load-file_test.go
+++ b/pkg/iac-providers/cft/v1/load-file_test.go
@@ -43,6 +43,7 @@ func TestLoadIacFile(t *testing.T) {
 		name     string
 		filePath string
 		typeOnly bool
+		options  map[string]interface{}
 	}{
 		{
 			wantErr:  fmt.Errorf(testErrString1),
@@ -77,7 +78,7 @@ func TestLoadIacFile(t *testing.T) {
 
 	for _, tt := range table {
 		t.Run(tt.name, func(t *testing.T) {
-			_, gotErr := tt.cftv1.LoadIacFile(tt.filePath)
+			_, gotErr := tt.cftv1.LoadIacFile(tt.filePath, tt.options)
 			if !reflect.DeepEqual(gotErr, tt.wantErr) {
 				t.Errorf("unexpected error; gotErr: '%+v', wantErr: '%+v'", gotErr, tt.wantErr)
 			} else if tt.typeOnly && (reflect.TypeOf(gotErr)) != reflect.TypeOf(tt.wantErr) {
diff --git a/pkg/iac-providers/docker/v1/load-dir_test.go b/pkg/iac-providers/docker/v1/load-dir_test.go
index 05679621d..437828324 100644
--- a/pkg/iac-providers/docker/v1/load-dir_test.go
+++ b/pkg/iac-providers/docker/v1/load-dir_test.go
@@ -41,6 +41,7 @@ func TestLoadIacDir(t *testing.T) {
 	tests := []struct {
 		name     string
 		dirPath  string
+		options  map[string]interface{}
 		dockerV1 DockerV1
 		want     output.AllResourceConfigs
 		wantErr  error
@@ -94,7 +95,7 @@ func TestLoadIacDir(t *testing.T) {
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
 
-			got, gotErr := tt.dockerV1.LoadIacDir(tt.dirPath, false)
+			got, gotErr := tt.dockerV1.LoadIacDir(tt.dirPath, tt.options)
 			me, ok := gotErr.(*multierror.Error)
 			if !ok {
 				t.Errorf("expected multierror.Error, got %T", gotErr)
diff --git a/pkg/iac-providers/docker/v1/load-file_test.go b/pkg/iac-providers/docker/v1/load-file_test.go
index 41ddf46a6..d80a59848 100644
--- a/pkg/iac-providers/docker/v1/load-file_test.go
+++ b/pkg/iac-providers/docker/v1/load-file_test.go
@@ -127,6 +127,7 @@ func TestLoadIacFile(t *testing.T) {
 	tests := []struct {
 		name        string
 		absFilePath string
+		options     map[string]interface{}
 		dockerV1    DockerV1
 		want        output.AllResourceConfigs
 		wantErr     error
@@ -155,7 +156,7 @@ func TestLoadIacFile(t *testing.T) {
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
 
-			got, gotErr := tt.dockerV1.LoadIacFile(tt.absFilePath)
+			got, gotErr := tt.dockerV1.LoadIacFile(tt.absFilePath, tt.options)
 			if tt.want != nil {
 				if got == nil || !reflect.DeepEqual(got, tt.want) {
 					t.Errorf("unexpected result; got: '%#v', want: '%v'", got, tt.want)
diff --git a/pkg/iac-providers/helm/v3/load-dir_test.go b/pkg/iac-providers/helm/v3/load-dir_test.go
index 32072e9b1..719ba2b45 100644
--- a/pkg/iac-providers/helm/v3/load-dir_test.go
+++ b/pkg/iac-providers/helm/v3/load-dir_test.go
@@ -45,6 +45,7 @@ func TestLoadIacDir(t *testing.T) {
 		name          string
 		dirPath       string
 		helmv3        HelmV3
+		options       map[string]interface{}
 		want          output.AllResourceConfigs
 		wantErr       error
 		resourceCount int
@@ -79,7 +80,7 @@ func TestLoadIacDir(t *testing.T) {
 
 	for _, tt := range table {
 		t.Run(tt.name, func(t *testing.T) {
-			resources, gotErr := tt.helmv3.LoadIacDir(tt.dirPath, false)
+			resources, gotErr := tt.helmv3.LoadIacDir(tt.dirPath, tt.options)
 			me, ok := gotErr.(*multierror.Error)
 			if !ok {
 				t.Errorf("expected multierror.Error, got %T", gotErr)
diff --git a/pkg/iac-providers/helm/v3/load-file_test.go b/pkg/iac-providers/helm/v3/load-file_test.go
index 95c27f10b..3bd5ca9a2 100644
--- a/pkg/iac-providers/helm/v3/load-file_test.go
+++ b/pkg/iac-providers/helm/v3/load-file_test.go
@@ -28,6 +28,7 @@ func TestLoadIacFile(t *testing.T) {
 	table := []struct {
 		name     string
 		filePath string
+		options  map[string]interface{}
 		helmv3   HelmV3
 		typeOnly bool
 		want     output.AllResourceConfigs
@@ -43,7 +44,7 @@ func TestLoadIacFile(t *testing.T) {
 
 	for _, tt := range table {
 		t.Run(tt.name, func(t *testing.T) {
-			_, gotErr := tt.helmv3.LoadIacFile(tt.filePath)
+			_, gotErr := tt.helmv3.LoadIacFile(tt.filePath, tt.options)
 			if !reflect.DeepEqual(gotErr, tt.wantErr) {
 				t.Errorf("unexpected error; gotErr: '%v', wantErr: '%v'", gotErr, tt.wantErr)
 			} else if tt.typeOnly && (reflect.TypeOf(gotErr)) != reflect.TypeOf(tt.wantErr) {
diff --git a/pkg/iac-providers/kubernetes/v1/load-dir_test.go b/pkg/iac-providers/kubernetes/v1/load-dir_test.go
index beb350f81..ac84f337e 100644
--- a/pkg/iac-providers/kubernetes/v1/load-dir_test.go
+++ b/pkg/iac-providers/kubernetes/v1/load-dir_test.go
@@ -39,6 +39,7 @@ func TestLoadIacDir(t *testing.T) {
 		name    string
 		dirPath string
 		k8sV1   K8sV1
+		options map[string]interface{}
 		want    output.AllResourceConfigs
 		wantErr error
 	}{
@@ -88,7 +89,7 @@ func TestLoadIacDir(t *testing.T) {
 
 	for _, tt := range table {
 		t.Run(tt.name, func(t *testing.T) {
-			_, gotErr := tt.k8sV1.LoadIacDir(tt.dirPath, false)
+			_, gotErr := tt.k8sV1.LoadIacDir(tt.dirPath, tt.options)
 			me, ok := gotErr.(*multierror.Error)
 			if !ok {
 				t.Errorf("expected multierror.Error, got %T", gotErr)
diff --git a/pkg/iac-providers/kubernetes/v1/load-file_test.go b/pkg/iac-providers/kubernetes/v1/load-file_test.go
index aa5737901..b42d18cd0 100644
--- a/pkg/iac-providers/kubernetes/v1/load-file_test.go
+++ b/pkg/iac-providers/kubernetes/v1/load-file_test.go
@@ -32,6 +32,7 @@ func TestLoadIacFile(t *testing.T) {
 	table := []struct {
 		name     string
 		filePath string
+		options  map[string]interface{}
 		k8sV1    K8sV1
 		typeOnly bool
 		want     output.AllResourceConfigs
@@ -80,7 +81,7 @@ func TestLoadIacFile(t *testing.T) {
 
 	for _, tt := range table {
 		t.Run(tt.name, func(t *testing.T) {
-			_, gotErr := tt.k8sV1.LoadIacFile(tt.filePath)
+			_, gotErr := tt.k8sV1.LoadIacFile(tt.filePath, tt.options)
 			if !reflect.DeepEqual(gotErr, tt.wantErr) {
 				t.Errorf("unexpected error; gotErr: '%v', wantErr: '%v'", gotErr, tt.wantErr)
 			} else if tt.typeOnly && (reflect.TypeOf(gotErr)) != reflect.TypeOf(tt.wantErr) {
diff --git a/pkg/iac-providers/kustomize/v3/load-dir_test.go b/pkg/iac-providers/kustomize/v3/load-dir_test.go
index c3932cc09..8c515a722 100644
--- a/pkg/iac-providers/kustomize/v3/load-dir_test.go
+++ b/pkg/iac-providers/kustomize/v3/load-dir_test.go
@@ -27,6 +27,7 @@ func TestLoadIacDir(t *testing.T) {
 		want          output.AllResourceConfigs
 		wantErr       error
 		resourceCount int
+		options       map[string]interface{}
 	}{
 		{
 			name:          "invalid dirPath",
@@ -90,7 +91,7 @@ func TestLoadIacDir(t *testing.T) {
 
 	for _, tt := range table {
 		t.Run(tt.name, func(t *testing.T) {
-			resourceMap, gotErr := tt.kustomize.LoadIacDir(tt.dirPath, false)
+			resourceMap, gotErr := tt.kustomize.LoadIacDir(tt.dirPath, tt.options)
 			me, ok := gotErr.(*multierror.Error)
 			if !ok {
 				t.Errorf("expected multierror.Error, got %T", gotErr)
@@ -123,6 +124,7 @@ func TestLoadKustomize(t *testing.T) {
 		want        output.AllResourceConfigs
 		wantErr     error
 		checkPrefix bool
+		options     map[string]interface{}
 	}{
 		{
 			name:     "simple-deployment",
diff --git a/pkg/iac-providers/kustomize/v3/load-file_test.go b/pkg/iac-providers/kustomize/v3/load-file_test.go
index 8d52917a8..b46553898 100644
--- a/pkg/iac-providers/kustomize/v3/load-file_test.go
+++ b/pkg/iac-providers/kustomize/v3/load-file_test.go
@@ -12,6 +12,7 @@ func TestLoadIacFile(t *testing.T) {
 	table := []struct {
 		name      string
 		filePath  string
+		options   map[string]interface{}
 		kustomize KustomizeV3
 		typeOnly  bool
 		want      output.AllResourceConfigs
@@ -27,7 +28,7 @@ func TestLoadIacFile(t *testing.T) {
 
 	for _, tt := range table {
 		t.Run(tt.name, func(t *testing.T) {
-			_, gotErr := tt.kustomize.LoadIacFile(tt.filePath)
+			_, gotErr := tt.kustomize.LoadIacFile(tt.filePath, tt.options)
 			if !reflect.DeepEqual(gotErr, tt.wantErr) {
 				t.Errorf("unexpected error; gotErr: '%v', wantErr: '%v'", gotErr, tt.wantErr)
 			} else if tt.typeOnly && (reflect.TypeOf(gotErr)) != reflect.TypeOf(tt.wantErr) {
diff --git a/pkg/iac-providers/terraform/commons/load-dir_test.go b/pkg/iac-providers/terraform/commons/load-dir_test.go
index 98ab7b2d1..8bd29f2a4 100644
--- a/pkg/iac-providers/terraform/commons/load-dir_test.go
+++ b/pkg/iac-providers/terraform/commons/load-dir_test.go
@@ -26,6 +26,7 @@ import (
 	"github.com/accurics/terrascan/pkg/utils"
 	"github.com/hashicorp/hcl/v2"
 	hclConfigs "github.com/hashicorp/terraform/configs"
+	"go.uber.org/zap"
 )
 
 // test data
@@ -47,9 +48,10 @@ func TestProcessLocalSource(t *testing.T) {
 		req *hclConfigs.ModuleRequest
 	}
 	tests := []struct {
-		name string
-		args args
-		want string
+		name    string
+		args    args
+		want    string
+		options map[string]interface{}
 	}{
 		{
 			name: "no remote module",
@@ -61,7 +63,7 @@ func TestProcessLocalSource(t *testing.T) {
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			dl := NewTerraformDirectoryLoader("", false)
+			dl := NewTerraformDirectoryLoader("", tt.options)
 			if got := dl.processLocalSource(tt.args.req); got != tt.want {
 				t.Errorf("processLocalSource() got = %v, want = %v", got, tt.want)
 			}
@@ -83,6 +85,7 @@ func TestProcessTerraformRegistrySource(t *testing.T) {
 		args    args
 		want    string
 		wantErr bool
+		options map[string]interface{}
 	}{
 		{
 			name: "invalid registry host",
@@ -112,7 +115,7 @@ func TestProcessTerraformRegistrySource(t *testing.T) {
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
 			defer os.RemoveAll(tt.args.tempDir)
-			dl := NewTerraformDirectoryLoader("", false)
+			dl := NewTerraformDirectoryLoader("", tt.options)
 			got, err := dl.processTerraformRegistrySource(tt.args.req, tt.args.tempDir)
 			if (err != nil) != tt.wantErr {
 				t.Errorf("processTerraformRegistrySource() got error = %v, wantErr = %v", err, tt.wantErr)
@@ -256,3 +259,68 @@ func TestGetConfigSource(t *testing.T) {
 		})
 	}
 }
+
+func TestGetRemoteModuleIfPresentInTerraformSrc(t *testing.T) {
+	absRootDir, err := filepath.Abs(filepath.Dir(filepath.Join("testdata", "terraform_cache_use_in_scan", "remote-module.tf")))
+	if err != nil {
+		zap.S().Error("error finding working directory", err)
+	}
+	terraformInitRegs := filepath.Join(absRootDir, terraformModuleInstallDir, "network")
+	type fields struct {
+		Cache map[string]TerraformModuleManifest
+	}
+	type args struct {
+		req *hclConfigs.ModuleRequest
+	}
+	tests := []struct {
+		name         string
+		fields       fields
+		args         args
+		wantSrc      string
+		wantDestpath string
+	}{
+		{
+			name: "module present in terraform cache",
+			fields: fields{
+				Cache: make(map[string]TerraformModuleManifest),
+			},
+			args: args{
+				req: &hclConfigs.ModuleRequest{
+					SourceAddr:      "Azure/network/azurerm",
+					SourceAddrRange: hcl.Range{Filename: filepath.Join("testdata", "terraform_cache_use_in_scan", "remote-module.tf")},
+				},
+			},
+			wantSrc:      "Azure/network/azurerm",
+			wantDestpath: terraformInitRegs,
+		},
+		{
+			name: "module not present in terraform cache",
+			fields: fields{
+				Cache: make(map[string]TerraformModuleManifest),
+			},
+			args: args{
+				req: &hclConfigs.ModuleRequest{
+					SourceAddr:      "Azure/network/azurermtest",
+					SourceAddrRange: hcl.Range{Filename: filepath.Join("testdata", "terraform_cache_use_in_scan", "remote-module.tf")},
+				},
+			},
+			wantSrc:      "",
+			wantDestpath: "",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			tr := &TerraformDirectoryLoader{
+				absRootDir:               absRootDir,
+				terraformInitModuleCache: tt.fields.Cache,
+			}
+			gotSrc, gotDestpath := tr.GetRemoteModuleIfPresentInTerraformSrc(tt.args.req)
+			if gotSrc != tt.wantSrc {
+				t.Errorf("TerraformModuleManifestCache.GetRemoteModuleIfPresentInTerraformSrc() gotSrc = %v, want %v", gotSrc, tt.wantSrc)
+			}
+			if gotDestpath != tt.wantDestpath {
+				t.Errorf("TerraformModuleManifestCache.GetRemoteModuleIfPresentInTerraformSrc() gotDestpath = %v, want %v", gotDestpath, tt.wantDestpath)
+			}
+		})
+	}
+}
diff --git a/pkg/iac-providers/terraform/commons/testdata/terraform_cache_use_in_scan/.terraform/modules/modules.json b/pkg/iac-providers/terraform/commons/testdata/terraform_cache_use_in_scan/.terraform/modules/modules.json
new file mode 100644
index 000000000..3f3723ed3
--- /dev/null
+++ b/pkg/iac-providers/terraform/commons/testdata/terraform_cache_use_in_scan/.terraform/modules/modules.json
@@ -0,0 +1,15 @@
+{
+    "Modules": [
+        {
+            "Key": "",
+            "Source": "",
+            "Dir": "."
+        },
+        {
+            "Key": "network",
+            "Source": "Azure/network/azurerm",
+            "Version": "3.2.1",
+            "Dir": ".terraform/modules/network"
+        }
+    ]
+}
\ No newline at end of file
diff --git a/pkg/iac-providers/terraform/commons/testdata/terraform_cache_use_in_scan/.terraform/modules/network/main.tf b/pkg/iac-providers/terraform/commons/testdata/terraform_cache_use_in_scan/.terraform/modules/network/main.tf
new file mode 100644
index 000000000..780f2118c
--- /dev/null
+++ b/pkg/iac-providers/terraform/commons/testdata/terraform_cache_use_in_scan/.terraform/modules/network/main.tf
@@ -0,0 +1,21 @@
+#Azure Generic vNet Module
+data "azurerm_resource_group" "network" {
+  name = var.resource_group_name
+}
+
+resource "azurerm_virtual_network" "vnet" {
+  name                = var.vnet_name
+  resource_group_name = data.azurerm_resource_group.network.name
+  location            = data.azurerm_resource_group.network.location
+  address_space       = [var.address_space]
+  dns_servers         = var.dns_servers
+  tags                = var.tags
+}
+
+resource "azurerm_subnet" "subnet" {
+  count                = length(var.subnet_names)
+  name                 = var.subnet_names[count.index]
+  resource_group_name  = data.azurerm_resource_group.network.name
+  address_prefixes     = [var.subnet_prefixes[count.index]]
+  virtual_network_name = azurerm_virtual_network.vnet.name
+}
diff --git a/pkg/iac-providers/terraform/commons/testdata/terraform_cache_use_in_scan/.terraform/modules/network/outputs.tf b/pkg/iac-providers/terraform/commons/testdata/terraform_cache_use_in_scan/.terraform/modules/network/outputs.tf
new file mode 100644
index 000000000..4534e0215
--- /dev/null
+++ b/pkg/iac-providers/terraform/commons/testdata/terraform_cache_use_in_scan/.terraform/modules/network/outputs.tf
@@ -0,0 +1,24 @@
+output "vnet_id" {
+  description = "The id of the newly created vNet"
+  value       = azurerm_virtual_network.vnet.id
+}
+
+output "vnet_name" {
+  description = "The Name of the newly created vNet"
+  value       = azurerm_virtual_network.vnet.name
+}
+
+output "vnet_location" {
+  description = "The location of the newly created vNet"
+  value       = azurerm_virtual_network.vnet.location
+}
+
+output "vnet_address_space" {
+  description = "The address space of the newly created vNet"
+  value       = azurerm_virtual_network.vnet.address_space
+}
+
+output "vnet_subnets" {
+  description = "The ids of subnets created inside the newl vNet"
+  value       = azurerm_subnet.subnet.*.id
+}
diff --git a/pkg/iac-providers/terraform/commons/testdata/terraform_cache_use_in_scan/.terraform/modules/network/variables.tf b/pkg/iac-providers/terraform/commons/testdata/terraform_cache_use_in_scan/.terraform/modules/network/variables.tf
new file mode 100644
index 000000000..3a964abf9
--- /dev/null
+++ b/pkg/iac-providers/terraform/commons/testdata/terraform_cache_use_in_scan/.terraform/modules/network/variables.tf
@@ -0,0 +1,44 @@
+variable "vnet_name" {
+  description = "Name of the vnet to create."
+  type        = string
+  default     = "acctvnet"
+}
+
+variable "resource_group_name" {
+  description = "The name of an existing resource group to be imported."
+  type        = string
+}
+
+variable "address_space" {
+  description = "The address space that is used by the virtual network."
+  type        = string
+  default     = "10.0.0.0/16"
+}
+
+# If no values specified, this defaults to Azure DNS 
+variable "dns_servers" {
+  description = "The DNS servers to be used with vNet."
+  type        = list(string)
+  default     = []
+}
+
+variable "subnet_prefixes" {
+  description = "The address prefix to use for the subnet."
+  type        = list(string)
+  default     = ["10.0.1.0/24"]
+}
+
+variable "subnet_names" {
+  description = "A list of public subnets inside the vNet."
+  type        = list(string)
+  default     = ["subnet1"]
+}
+
+variable "tags" {
+  description = "The tags to associate with your network and subnets."
+  type        = map(string)
+
+  default = {
+    environment = "dev"
+  }
+}
diff --git a/pkg/iac-providers/terraform/commons/testdata/terraform_cache_use_in_scan/remote-module.tf b/pkg/iac-providers/terraform/commons/testdata/terraform_cache_use_in_scan/remote-module.tf
new file mode 100644
index 000000000..fb88de2fd
--- /dev/null
+++ b/pkg/iac-providers/terraform/commons/testdata/terraform_cache_use_in_scan/remote-module.tf
@@ -0,0 +1,9 @@
+#file added for fix for #418
+
+# source https://registry.terraform.io/
+
+module "network" {
+  source  = "Azure/network/azurerm"
+  version = "3.2.1"
+}
+
diff --git a/pkg/iac-providers/terraform/v12/load-dir_test.go b/pkg/iac-providers/terraform/v12/load-dir_test.go
index 262fca7cd..86de9ea30 100644
--- a/pkg/iac-providers/terraform/v12/load-dir_test.go
+++ b/pkg/iac-providers/terraform/v12/load-dir_test.go
@@ -82,19 +82,21 @@ References to other resources during the destroy phase can cause dependency cycl
 	}
 
 	table := []struct {
-		name         string
-		dirPath      string
-		tfv12        TfV12
-		want         output.AllResourceConfigs
-		nonRecursive bool
-		wantErr      error
+		name    string
+		dirPath string
+		tfv12   TfV12
+		want    output.AllResourceConfigs
+		wantErr error
+		options map[string]interface{}
 	}{
 		{
-			name:         "invalid dirPath",
-			dirPath:      testDirPath1,
-			tfv12:        TfV12{},
-			nonRecursive: true,
-			wantErr:      multierror.Append(fmt.Errorf(invalidDirErrStringTemplate, testDirPath1)),
+			name:    "invalid dirPath",
+			dirPath: testDirPath1,
+			tfv12:   TfV12{},
+			options: map[string]interface{}{
+				"nonRecursive": true,
+			},
+			wantErr: multierror.Append(fmt.Errorf(invalidDirErrStringTemplate, testDirPath1)),
 		},
 		{
 			name:    "invalid dirPath recursive",
@@ -103,11 +105,13 @@ References to other resources during the destroy phase can cause dependency cycl
 			wantErr: multierror.Append(pathErr),
 		},
 		{
-			name:         "empty config",
-			dirPath:      testDirPath2,
-			tfv12:        TfV12{},
-			nonRecursive: true,
-			wantErr:      multierror.Append(fmt.Errorf(invalidDirErrStringTemplate, testDirPath2)),
+			name:    "empty config",
+			dirPath: testDirPath2,
+			tfv12:   TfV12{},
+			options: map[string]interface{}{
+				"nonRecursive": true,
+			},
+			wantErr: multierror.Append(fmt.Errorf(invalidDirErrStringTemplate, testDirPath2)),
 		},
 		{
 			name:    "empty config recursive",
@@ -116,11 +120,13 @@ References to other resources during the destroy phase can cause dependency cycl
 			wantErr: nilMultiErr,
 		},
 		{
-			name:         "incorrect module structure",
-			dirPath:      filepath.Join(testDataDir, "invalid-moduleconfigs"),
-			tfv12:        TfV12{},
-			nonRecursive: true,
-			wantErr:      multierror.Append(fmt.Errorf("failed to build terraform allResourcesConfig")),
+			name:    "incorrect module structure",
+			dirPath: filepath.Join(testDataDir, "invalid-moduleconfigs"),
+			tfv12:   TfV12{},
+			options: map[string]interface{}{
+				"nonRecursive": true,
+			},
+			wantErr: multierror.Append(fmt.Errorf("failed to build terraform allResourcesConfig")),
 		},
 		{
 			name:    "incorrect module structure recursive",
@@ -130,11 +136,13 @@ References to other resources during the destroy phase can cause dependency cycl
 			wantErr: multierror.Append(fmt.Errorf(errStringInvalidModuleConfigs), fmt.Errorf(errStringInvalidModuleConfigs)),
 		},
 		{
-			name:         "load invalid config dir",
-			dirPath:      testDataDir,
-			tfv12:        TfV12{},
-			nonRecursive: true,
-			wantErr:      multierror.Append(fmt.Errorf(testErrorString1)),
+			name:    "load invalid config dir",
+			dirPath: testDataDir,
+			tfv12:   TfV12{},
+			options: map[string]interface{}{
+				"nonRecursive": true,
+			},
+			wantErr: multierror.Append(fmt.Errorf(testErrorString1)),
 		},
 		{
 			name:    "load invalid config dir recursive",
@@ -154,11 +162,13 @@ References to other resources during the destroy phase can cause dependency cycl
 			),
 		},
 		{
-			name:         "load multiple provider config dir",
-			dirPath:      multipleProvidersDir,
-			tfv12:        TfV12{},
-			nonRecursive: true,
-			wantErr:      multierror.Append(fmt.Errorf(testErrorString2)),
+			name:    "load multiple provider config dir",
+			dirPath: multipleProvidersDir,
+			tfv12:   TfV12{},
+			options: map[string]interface{}{
+				"nonRecursive": true,
+			},
+			wantErr: multierror.Append(fmt.Errorf(testErrorString2)),
 		},
 		{
 			name:    "load multiple provider config dir recursive",
@@ -176,7 +186,7 @@ References to other resources during the destroy phase can cause dependency cycl
 
 	for _, tt := range table {
 		t.Run(tt.name, func(t *testing.T) {
-			_, gotErr := tt.tfv12.LoadIacDir(tt.dirPath, tt.nonRecursive)
+			_, gotErr := tt.tfv12.LoadIacDir(tt.dirPath, tt.options)
 			me, ok := gotErr.(*multierror.Error)
 			if !ok {
 				t.Errorf("expected multierror.Error, got %T", gotErr)
@@ -195,20 +205,22 @@ References to other resources during the destroy phase can cause dependency cycl
 	nestedModuleErr2 := fmt.Errorf(invalidDirErrStringTemplate, filepath.Join(testDataDir, "deep-modules", "modules", "m4", "modules"))
 
 	table2 := []struct {
-		name         string
-		tfConfigDir  string
-		tfJSONFile   string
-		tfv12        TfV12
-		nonRecursive bool
-		wantErr      error
+		name        string
+		tfConfigDir string
+		tfJSONFile  string
+		tfv12       TfV12
+		options     map[string]interface{}
+		wantErr     error
 	}{
 		{
-			name:         "config1",
-			tfConfigDir:  filepath.Join(testDataDir, "tfconfigs"),
-			tfJSONFile:   filepath.Join(tfJSONDir, "fullconfig.json"),
-			tfv12:        TfV12{},
-			nonRecursive: true,
-			wantErr:      nilMultiErr,
+			name:        "config1",
+			tfConfigDir: filepath.Join(testDataDir, "tfconfigs"),
+			tfJSONFile:  filepath.Join(tfJSONDir, "fullconfig.json"),
+			tfv12:       TfV12{},
+			options: map[string]interface{}{
+				"nonRecursive": true,
+			},
+			wantErr: nilMultiErr,
 		},
 		{
 			name:        "config1 recursive",
@@ -219,12 +231,14 @@ References to other resources during the destroy phase can cause dependency cycl
 			wantErr:    nilMultiErr,
 		},
 		{
-			name:         "module directory",
-			tfConfigDir:  filepath.Join(testDataDir, "moduleconfigs"),
-			tfJSONFile:   filepath.Join(tfJSONDir, "moduleconfigs.json"),
-			tfv12:        TfV12{},
-			nonRecursive: true,
-			wantErr:      nilMultiErr,
+			name:        "module directory",
+			tfConfigDir: filepath.Join(testDataDir, "moduleconfigs"),
+			tfJSONFile:  filepath.Join(tfJSONDir, "moduleconfigs.json"),
+			tfv12:       TfV12{},
+			options: map[string]interface{}{
+				"nonRecursive": true,
+			},
+			wantErr: nilMultiErr,
 		},
 		{
 			name:        "module directory recursive",
@@ -235,12 +249,14 @@ References to other resources during the destroy phase can cause dependency cycl
 			wantErr:    nilMultiErr,
 		},
 		{
-			name:         "nested module directory",
-			tfConfigDir:  filepath.Join(testDataDir, "deep-modules"),
-			tfJSONFile:   filepath.Join(tfJSONDir, "deep-modules.json"),
-			tfv12:        TfV12{},
-			nonRecursive: true,
-			wantErr:      nilMultiErr,
+			name:        "nested module directory",
+			tfConfigDir: filepath.Join(testDataDir, "deep-modules"),
+			tfJSONFile:  filepath.Join(tfJSONDir, "deep-modules.json"),
+			tfv12:       TfV12{},
+			options: map[string]interface{}{
+				"nonRecursive": true,
+			},
+			wantErr: nilMultiErr,
 		},
 		{
 			name:        "variables of list type",
@@ -260,7 +276,7 @@ References to other resources during the destroy phase can cause dependency cycl
 
 	for _, tt := range table2 {
 		t.Run(tt.name, func(t *testing.T) {
-			got, gotErr := tt.tfv12.LoadIacDir(tt.tfConfigDir, tt.nonRecursive)
+			got, gotErr := tt.tfv12.LoadIacDir(tt.tfConfigDir, tt.options)
 			me, ok := gotErr.(*multierror.Error)
 			if !ok {
 				t.Errorf("expected multierror.Error, got %T", gotErr)
diff --git a/pkg/iac-providers/terraform/v12/load-file_test.go b/pkg/iac-providers/terraform/v12/load-file_test.go
index 8468087aa..d75cfc492 100644
--- a/pkg/iac-providers/terraform/v12/load-file_test.go
+++ b/pkg/iac-providers/terraform/v12/load-file_test.go
@@ -59,6 +59,7 @@ References to other resources during the destroy phase can cause dependency cycl
 	table := []struct {
 		name     string
 		filePath string
+		options  map[string]interface{}
 		tfv12    TfV12
 		want     output.AllResourceConfigs
 		wantErr  error
@@ -90,7 +91,7 @@ References to other resources during the destroy phase can cause dependency cycl
 
 	for _, tt := range table {
 		t.Run(tt.name, func(t *testing.T) {
-			_, gotErr := tt.tfv12.LoadIacFile(tt.filePath)
+			_, gotErr := tt.tfv12.LoadIacFile(tt.filePath, tt.options)
 			if !reflect.DeepEqual(gotErr, tt.wantErr) {
 				t.Errorf("unexpected error; gotErr: '%v', wantErr: '%v'", gotErr, tt.wantErr)
 			}
@@ -101,6 +102,7 @@ References to other resources during the destroy phase can cause dependency cycl
 		name         string
 		tfConfigFile string
 		tfJSONFile   string
+		options      map[string]interface{}
 		tfv12        TfV12
 		wantErr      error
 	}{
@@ -122,7 +124,7 @@ References to other resources during the destroy phase can cause dependency cycl
 
 	for _, tt := range table2 {
 		t.Run(tt.name, func(t *testing.T) {
-			got, gotErr := tt.tfv12.LoadIacFile(tt.tfConfigFile)
+			got, gotErr := tt.tfv12.LoadIacFile(tt.tfConfigFile, tt.options)
 			if !reflect.DeepEqual(gotErr, tt.wantErr) {
 				t.Errorf("unexpected error; gotErr: '%v', wantErr: '%v'", gotErr, tt.wantErr)
 			}
diff --git a/pkg/iac-providers/terraform/v14/load-dir_test.go b/pkg/iac-providers/terraform/v14/load-dir_test.go
index aa9bb7c70..3384385af 100644
--- a/pkg/iac-providers/terraform/v14/load-dir_test.go
+++ b/pkg/iac-providers/terraform/v14/load-dir_test.go
@@ -63,19 +63,21 @@ func TestLoadIacDir(t *testing.T) {
 	}
 
 	table := []struct {
-		name         string
-		dirPath      string
-		tfv14        TfV14
-		want         output.AllResourceConfigs
-		nonRecursive bool
-		wantErr      error
+		name    string
+		dirPath string
+		tfv14   TfV14
+		want    output.AllResourceConfigs
+		options map[string]interface{}
+		wantErr error
 	}{
 		{
-			name:         "invalid dirPath",
-			dirPath:      testDirPath1,
-			tfv14:        TfV14{},
-			nonRecursive: true,
-			wantErr:      multierror.Append(fmt.Errorf(invalidDirErrStringTemplate, testDirPath1)),
+			name:    "invalid dirPath",
+			dirPath: testDirPath1,
+			tfv14:   TfV14{},
+			options: map[string]interface{}{
+				"nonRecursive": true,
+			},
+			wantErr: multierror.Append(fmt.Errorf(invalidDirErrStringTemplate, testDirPath1)),
 		},
 		{
 			name:    "invalid dirPath recursive",
@@ -84,11 +86,13 @@ func TestLoadIacDir(t *testing.T) {
 			wantErr: multierror.Append(pathErr),
 		},
 		{
-			name:         "empty config",
-			dirPath:      testDirPath2,
-			tfv14:        TfV14{},
-			nonRecursive: true,
-			wantErr:      multierror.Append(fmt.Errorf(invalidDirErrStringTemplate, testDirPath2)),
+			name:    "empty config",
+			dirPath: testDirPath2,
+			tfv14:   TfV14{},
+			options: map[string]interface{}{
+				"nonRecursive": true,
+			},
+			wantErr: multierror.Append(fmt.Errorf(invalidDirErrStringTemplate, testDirPath2)),
 		},
 		{
 			name:    "empty config recursive",
@@ -97,11 +101,13 @@ func TestLoadIacDir(t *testing.T) {
 			wantErr: nilMultiErr,
 		},
 		{
-			name:         "incorrect module structure",
-			dirPath:      filepath.Join(testDataDir, "invalid-moduleconfigs"),
-			tfv14:        TfV14{},
-			nonRecursive: true,
-			wantErr:      multierror.Append(fmt.Errorf("failed to build terraform allResourcesConfig")),
+			name:    "incorrect module structure",
+			dirPath: filepath.Join(testDataDir, "invalid-moduleconfigs"),
+			tfv14:   TfV14{},
+			options: map[string]interface{}{
+				"nonRecursive": true,
+			},
+			wantErr: multierror.Append(fmt.Errorf("failed to build terraform allResourcesConfig")),
 		},
 		{
 			name:    "incorrect module structure recursive",
@@ -111,11 +117,13 @@ func TestLoadIacDir(t *testing.T) {
 			wantErr: multierror.Append(fmt.Errorf(errStringInvalidModuleConfigs), fmt.Errorf(errStringInvalidModuleConfigs)),
 		},
 		{
-			name:         "load invalid config dir",
-			dirPath:      testDataDir,
-			tfv14:        TfV14{},
-			nonRecursive: true,
-			wantErr:      multierror.Append(fmt.Errorf(testErrorMessage)),
+			name:    "load invalid config dir",
+			dirPath: testDataDir,
+			tfv14:   TfV14{},
+			options: map[string]interface{}{
+				"nonRecursive": true,
+			},
+			wantErr: multierror.Append(fmt.Errorf(testErrorMessage)),
 		},
 		{
 			name:    "load invalid config dir recursive",
@@ -143,7 +151,7 @@ func TestLoadIacDir(t *testing.T) {
 
 	for _, tt := range table {
 		t.Run(tt.name, func(t *testing.T) {
-			_, gotErr := tt.tfv14.LoadIacDir(tt.dirPath, tt.nonRecursive)
+			_, gotErr := tt.tfv14.LoadIacDir(tt.dirPath, tt.options)
 			me, ok := gotErr.(*multierror.Error)
 			if !ok {
 				t.Errorf("expected multierror.Error, got %T", gotErr)
@@ -163,20 +171,22 @@ func TestLoadIacDir(t *testing.T) {
 	nestedModuleErr2 := fmt.Errorf(invalidDirErrStringTemplate, filepath.Join(testDataDir, "deep-modules", "modules", "m4", "modules"))
 
 	table2 := []struct {
-		name         string
-		tfConfigDir  string
-		tfJSONFile   string
-		tfv14        TfV14
-		nonRecursive bool
-		wantErr      error
+		name        string
+		tfConfigDir string
+		tfJSONFile  string
+		tfv14       TfV14
+		options     map[string]interface{}
+		wantErr     error
 	}{
 		{
-			name:         "config1",
-			tfConfigDir:  filepath.Join(testDataDir, "tfconfigs"),
-			tfJSONFile:   filepath.Join(tfJSONDir, "fullconfig.json"),
-			tfv14:        TfV14{},
-			nonRecursive: true,
-			wantErr:      nilMultiErr,
+			name:        "config1",
+			tfConfigDir: filepath.Join(testDataDir, "tfconfigs"),
+			tfJSONFile:  filepath.Join(tfJSONDir, "fullconfig.json"),
+			tfv14:       TfV14{},
+			options: map[string]interface{}{
+				"nonRecursive": true,
+			},
+			wantErr: nilMultiErr,
 		},
 		{
 			name:        "config1 recursive",
@@ -187,12 +197,14 @@ func TestLoadIacDir(t *testing.T) {
 			wantErr:    nilMultiErr,
 		},
 		{
-			name:         "module directory",
-			tfConfigDir:  filepath.Join(testDataDir, "moduleconfigs"),
-			tfJSONFile:   filepath.Join(tfJSONDir, "moduleconfigs.json"),
-			tfv14:        TfV14{},
-			nonRecursive: true,
-			wantErr:      nilMultiErr,
+			name:        "module directory",
+			tfConfigDir: filepath.Join(testDataDir, "moduleconfigs"),
+			tfJSONFile:  filepath.Join(tfJSONDir, "moduleconfigs.json"),
+			tfv14:       TfV14{},
+			options: map[string]interface{}{
+				"nonRecursive": true,
+			},
+			wantErr: nilMultiErr,
 		},
 		{
 			name:        "module directory recursive",
@@ -203,12 +215,14 @@ func TestLoadIacDir(t *testing.T) {
 			wantErr:    nilMultiErr,
 		},
 		{
-			name:         "nested module directory",
-			tfConfigDir:  filepath.Join(testDataDir, "deep-modules"),
-			tfJSONFile:   filepath.Join(tfJSONDir, "deep-modules.json"),
-			tfv14:        TfV14{},
-			nonRecursive: true,
-			wantErr:      nilMultiErr,
+			name:        "nested module directory",
+			tfConfigDir: filepath.Join(testDataDir, "deep-modules"),
+			tfJSONFile:  filepath.Join(tfJSONDir, "deep-modules.json"),
+			tfv14:       TfV14{},
+			options: map[string]interface{}{
+				"nonRecursive": true,
+			},
+			wantErr: nilMultiErr,
 		},
 		{
 			name:        "nested module directory recursive",
@@ -218,42 +232,50 @@ func TestLoadIacDir(t *testing.T) {
 			wantErr:     multierror.Append(nestedModuleErr1, nestedModuleErr2),
 		},
 		{
-			name:         "complex variables",
-			tfConfigDir:  filepath.Join(testDataDir, "complex-variables"),
-			tfJSONFile:   filepath.Join(tfJSONDir, "complex-variables.json"),
-			tfv14:        TfV14{},
-			nonRecursive: true,
-			wantErr:      nilMultiErr,
+			name:        "complex variables",
+			tfConfigDir: filepath.Join(testDataDir, "complex-variables"),
+			tfJSONFile:  filepath.Join(tfJSONDir, "complex-variables.json"),
+			tfv14:       TfV14{},
+			options: map[string]interface{}{
+				"nonRecursive": true,
+			},
+			wantErr: nilMultiErr,
 		},
 		{
-			name:         "recursive loop while resolving variables",
-			tfConfigDir:  filepath.Join(testDataDir, "recursive-loop-variables"),
-			tfJSONFile:   filepath.Join(tfJSONDir, "recursive-loop-variables.json"),
-			tfv14:        TfV14{},
-			nonRecursive: true,
-			wantErr:      nilMultiErr,
+			name:        "recursive loop while resolving variables",
+			tfConfigDir: filepath.Join(testDataDir, "recursive-loop-variables"),
+			tfJSONFile:  filepath.Join(tfJSONDir, "recursive-loop-variables.json"),
+			tfv14:       TfV14{},
+			options: map[string]interface{}{
+				"nonRecursive": true,
+			},
+			wantErr: nilMultiErr,
 		},
 		{
-			name:         "recursive loop while resolving locals",
-			tfConfigDir:  filepath.Join(testDataDir, "recursive-loop-locals"),
-			tfJSONFile:   filepath.Join(tfJSONDir, "recursive-loop-locals.json"),
-			tfv14:        TfV14{},
-			nonRecursive: true,
-			wantErr:      nilMultiErr,
+			name:        "recursive loop while resolving locals",
+			tfConfigDir: filepath.Join(testDataDir, "recursive-loop-locals"),
+			tfJSONFile:  filepath.Join(tfJSONDir, "recursive-loop-locals.json"),
+			tfv14:       TfV14{},
+			options: map[string]interface{}{
+				"nonRecursive": true,
+			},
+			wantErr: nilMultiErr,
 		},
 		{
-			name:         "recursive loop while resolving locals with same name in parent and child module",
-			tfConfigDir:  filepath.Join(testDataDir, "recursive-loop-duplicate-locals"),
-			tfJSONFile:   filepath.Join(tfJSONDir, "recursive-loop-duplicate-locals.json"),
-			tfv14:        TfV14{},
-			nonRecursive: true,
-			wantErr:      nilMultiErr,
+			name:        "recursive loop while resolving locals with same name in parent and child module",
+			tfConfigDir: filepath.Join(testDataDir, "recursive-loop-duplicate-locals"),
+			tfJSONFile:  filepath.Join(tfJSONDir, "recursive-loop-duplicate-locals.json"),
+			tfv14:       TfV14{},
+			options: map[string]interface{}{
+				"nonRecursive": true,
+			},
+			wantErr: nilMultiErr,
 		},
 	}
 
 	for _, tt := range table2 {
 		t.Run(tt.name, func(t *testing.T) {
-			got, gotErr := tt.tfv14.LoadIacDir(tt.tfConfigDir, tt.nonRecursive)
+			got, gotErr := tt.tfv14.LoadIacDir(tt.tfConfigDir, tt.options)
 			me, ok := gotErr.(*multierror.Error)
 			if !ok {
 				t.Errorf("expected multierror.Error, got %T", gotErr)
diff --git a/pkg/iac-providers/terraform/v14/load-file_test.go b/pkg/iac-providers/terraform/v14/load-file_test.go
index e872f223c..df34ef24e 100644
--- a/pkg/iac-providers/terraform/v14/load-file_test.go
+++ b/pkg/iac-providers/terraform/v14/load-file_test.go
@@ -47,6 +47,7 @@ func TestLoadIacFile(t *testing.T) {
 		name     string
 		filePath string
 		tfv14    TfV14
+		options  map[string]interface{}
 		want     output.AllResourceConfigs
 		wantErr  error
 	}{
@@ -91,7 +92,7 @@ func TestLoadIacFile(t *testing.T) {
 
 	for _, tt := range table {
 		t.Run(tt.name, func(t *testing.T) {
-			_, gotErr := tt.tfv14.LoadIacFile(tt.filePath)
+			_, gotErr := tt.tfv14.LoadIacFile(tt.filePath, tt.options)
 			if !reflect.DeepEqual(gotErr, tt.wantErr) {
 				t.Errorf("unexpected error; gotErr: '%v', wantErr: '%v'", gotErr, tt.wantErr)
 			}
@@ -102,6 +103,7 @@ func TestLoadIacFile(t *testing.T) {
 		name         string
 		tfConfigFile string
 		tfJSONFile   string
+		options      map[string]interface{}
 		tfv14        TfV14
 		wantErr      error
 	}{
@@ -123,7 +125,7 @@ func TestLoadIacFile(t *testing.T) {
 
 	for _, tt := range table2 {
 		t.Run(tt.name, func(t *testing.T) {
-			got, gotErr := tt.tfv14.LoadIacFile(tt.tfConfigFile)
+			got, gotErr := tt.tfv14.LoadIacFile(tt.tfConfigFile, tt.options)
 			if !reflect.DeepEqual(gotErr, tt.wantErr) {
 				t.Errorf("unexpected error; gotErr: '%v', wantErr: '%v'", gotErr, tt.wantErr)
 			}
diff --git a/pkg/iac-providers/terraform/v15/load-dir_test.go b/pkg/iac-providers/terraform/v15/load-dir_test.go
index ba47c0bbc..e8c4bad2b 100644
--- a/pkg/iac-providers/terraform/v15/load-dir_test.go
+++ b/pkg/iac-providers/terraform/v15/load-dir_test.go
@@ -63,19 +63,21 @@ func TestLoadIacDir(t *testing.T) {
 	}
 
 	table := []struct {
-		name         string
-		dirPath      string
-		tfv15        TfV15
-		want         output.AllResourceConfigs
-		nonRecursive bool
-		wantErr      error
+		name    string
+		dirPath string
+		tfv15   TfV15
+		want    output.AllResourceConfigs
+		wantErr error
+		options map[string]interface{}
 	}{
 		{
-			name:         "invalid dirPath",
-			dirPath:      testDirPath1,
-			tfv15:        TfV15{},
-			nonRecursive: true,
-			wantErr:      multierror.Append(fmt.Errorf(invalidDirErrStringTemplate, testDirPath1)),
+			name:    "invalid dirPath",
+			dirPath: testDirPath1,
+			tfv15:   TfV15{},
+			options: map[string]interface{}{
+				"nonRecursive": true,
+			},
+			wantErr: multierror.Append(fmt.Errorf(invalidDirErrStringTemplate, testDirPath1)),
 		},
 		{
 			name:    "invalid dirPath recursive",
@@ -84,11 +86,13 @@ func TestLoadIacDir(t *testing.T) {
 			wantErr: multierror.Append(pathErr),
 		},
 		{
-			name:         "empty config",
-			dirPath:      testDirPath2,
-			tfv15:        TfV15{},
-			nonRecursive: true,
-			wantErr:      multierror.Append(fmt.Errorf(invalidDirErrStringTemplate, testDirPath2)),
+			name:    "empty config",
+			dirPath: testDirPath2,
+			tfv15:   TfV15{},
+			options: map[string]interface{}{
+				"nonRecursive": true,
+			},
+			wantErr: multierror.Append(fmt.Errorf(invalidDirErrStringTemplate, testDirPath2)),
 		},
 		{
 			name:    "empty config recursive",
@@ -97,11 +101,13 @@ func TestLoadIacDir(t *testing.T) {
 			wantErr: nilMultiErr,
 		},
 		{
-			name:         "incorrect module structure",
-			dirPath:      filepath.Join(testDataDir, "invalid-moduleconfigs"),
-			tfv15:        TfV15{},
-			nonRecursive: true,
-			wantErr:      multierror.Append(fmt.Errorf("failed to build terraform allResourcesConfig")),
+			name:    "incorrect module structure",
+			dirPath: filepath.Join(testDataDir, "invalid-moduleconfigs"),
+			tfv15:   TfV15{},
+			options: map[string]interface{}{
+				"nonRecursive": true,
+			},
+			wantErr: multierror.Append(fmt.Errorf("failed to build terraform allResourcesConfig")),
 		},
 		{
 			name:    "incorrect module structure recursive",
@@ -111,11 +117,13 @@ func TestLoadIacDir(t *testing.T) {
 			wantErr: multierror.Append(fmt.Errorf(errStringInvalidModuleConfigs), fmt.Errorf(errStringInvalidModuleConfigs)),
 		},
 		{
-			name:         "load invalid config dir",
-			dirPath:      testDataDir,
-			tfv15:        TfV15{},
-			nonRecursive: true,
-			wantErr:      multierror.Append(fmt.Errorf(testErrorMessage)),
+			name:    "load invalid config dir",
+			dirPath: testDataDir,
+			tfv15:   TfV15{},
+			options: map[string]interface{}{
+				"nonRecursive": true,
+			},
+			wantErr: multierror.Append(fmt.Errorf(testErrorMessage)),
 		},
 		{
 			name:    "load invalid config dir recursive",
@@ -155,7 +163,7 @@ func TestLoadIacDir(t *testing.T) {
 
 	for _, tt := range table {
 		t.Run(tt.name, func(t *testing.T) {
-			_, gotErr := tt.tfv15.LoadIacDir(tt.dirPath, tt.nonRecursive)
+			_, gotErr := tt.tfv15.LoadIacDir(tt.dirPath, tt.options)
 			me, ok := gotErr.(*multierror.Error)
 			if !ok {
 				t.Errorf("expected multierror.Error, got %T", gotErr)
@@ -175,20 +183,22 @@ func TestLoadIacDir(t *testing.T) {
 	nestedModuleErr2 := fmt.Errorf(invalidDirErrStringTemplate, filepath.Join(testDataDir, "deep-modules", "modules", "m4", "modules"))
 
 	table2 := []struct {
-		name         string
-		tfConfigDir  string
-		tfJSONFile   string
-		tfv15        TfV15
-		nonRecursive bool
-		wantErr      error
+		name        string
+		tfConfigDir string
+		tfJSONFile  string
+		tfv15       TfV15
+		wantErr     error
+		options     map[string]interface{}
 	}{
 		{
-			name:         "config1",
-			tfConfigDir:  filepath.Join(testDataDir, "tfconfigs"),
-			tfJSONFile:   filepath.Join(tfJSONDir, "fullconfig.json"),
-			tfv15:        TfV15{},
-			nonRecursive: true,
-			wantErr:      nilMultiErr,
+			name:        "config1",
+			tfConfigDir: filepath.Join(testDataDir, "tfconfigs"),
+			tfJSONFile:  filepath.Join(tfJSONDir, "fullconfig.json"),
+			tfv15:       TfV15{},
+			options: map[string]interface{}{
+				"nonRecursive": true,
+			},
+			wantErr: nilMultiErr,
 		},
 		{
 			name:        "config1 recursive",
@@ -199,12 +209,14 @@ func TestLoadIacDir(t *testing.T) {
 			wantErr:    nilMultiErr,
 		},
 		{
-			name:         "module directory",
-			tfConfigDir:  filepath.Join(testDataDir, "moduleconfigs"),
-			tfJSONFile:   filepath.Join(tfJSONDir, "moduleconfigs.json"),
-			tfv15:        TfV15{},
-			nonRecursive: true,
-			wantErr:      nilMultiErr,
+			name:        "module directory",
+			tfConfigDir: filepath.Join(testDataDir, "moduleconfigs"),
+			tfJSONFile:  filepath.Join(tfJSONDir, "moduleconfigs.json"),
+			tfv15:       TfV15{},
+			options: map[string]interface{}{
+				"nonRecursive": true,
+			},
+			wantErr: nilMultiErr,
 		},
 		{
 			name:        "module directory recursive",
@@ -215,12 +227,14 @@ func TestLoadIacDir(t *testing.T) {
 			wantErr:    nilMultiErr,
 		},
 		{
-			name:         "nested module directory",
-			tfConfigDir:  filepath.Join(testDataDir, "deep-modules"),
-			tfJSONFile:   filepath.Join(tfJSONDir, "deep-modules.json"),
-			tfv15:        TfV15{},
-			nonRecursive: true,
-			wantErr:      nilMultiErr,
+			name:        "nested module directory",
+			tfConfigDir: filepath.Join(testDataDir, "deep-modules"),
+			tfJSONFile:  filepath.Join(tfJSONDir, "deep-modules.json"),
+			tfv15:       TfV15{},
+			options: map[string]interface{}{
+				"nonRecursive": true,
+			},
+			wantErr: nilMultiErr,
 		},
 		{
 			name:        "nested module directory recursive",
@@ -230,34 +244,40 @@ func TestLoadIacDir(t *testing.T) {
 			wantErr:     multierror.Append(nestedModuleErr1, nestedModuleErr2),
 		},
 		{
-			name:         "complex variables",
-			tfConfigDir:  filepath.Join(testDataDir, "complex-variables"),
-			tfJSONFile:   filepath.Join(tfJSONDir, "complex-variables.json"),
-			tfv15:        TfV15{},
-			nonRecursive: true,
-			wantErr:      nilMultiErr,
+			name:        "complex variables",
+			tfConfigDir: filepath.Join(testDataDir, "complex-variables"),
+			tfJSONFile:  filepath.Join(tfJSONDir, "complex-variables.json"),
+			tfv15:       TfV15{},
+			options: map[string]interface{}{
+				"nonRecursive": true,
+			},
+			wantErr: nilMultiErr,
 		},
 		{
-			name:         "recursive loop while resolving variables",
-			tfConfigDir:  filepath.Join(testDataDir, "recursive-loop-variables"),
-			tfJSONFile:   filepath.Join(tfJSONDir, "recursive-loop-variables.json"),
-			tfv15:        TfV15{},
-			nonRecursive: true,
-			wantErr:      nilMultiErr,
+			name:        "recursive loop while resolving variables",
+			tfConfigDir: filepath.Join(testDataDir, "recursive-loop-variables"),
+			tfJSONFile:  filepath.Join(tfJSONDir, "recursive-loop-variables.json"),
+			tfv15:       TfV15{},
+			options: map[string]interface{}{
+				"nonRecursive": true,
+			},
+			wantErr: nilMultiErr,
 		},
 		{
-			name:         "recursive loop while resolving locals",
-			tfConfigDir:  filepath.Join(testDataDir, "recursive-loop-locals"),
-			tfJSONFile:   filepath.Join(tfJSONDir, "recursive-loop-locals.json"),
-			tfv15:        TfV15{},
-			nonRecursive: true,
-			wantErr:      nilMultiErr,
+			name:        "recursive loop while resolving locals",
+			tfConfigDir: filepath.Join(testDataDir, "recursive-loop-locals"),
+			tfJSONFile:  filepath.Join(tfJSONDir, "recursive-loop-locals.json"),
+			tfv15:       TfV15{},
+			options: map[string]interface{}{
+				"nonRecursive": true,
+			},
+			wantErr: nilMultiErr,
 		},
 	}
 
 	for _, tt := range table2 {
 		t.Run(tt.name, func(t *testing.T) {
-			got, gotErr := tt.tfv15.LoadIacDir(tt.tfConfigDir, tt.nonRecursive)
+			got, gotErr := tt.tfv15.LoadIacDir(tt.tfConfigDir, tt.options)
 			me, ok := gotErr.(*multierror.Error)
 			if !ok {
 				t.Errorf("expected multierror.Error, got %T", gotErr)
diff --git a/pkg/iac-providers/terraform/v15/load-file_test.go b/pkg/iac-providers/terraform/v15/load-file_test.go
index d0cc358b8..126008435 100644
--- a/pkg/iac-providers/terraform/v15/load-file_test.go
+++ b/pkg/iac-providers/terraform/v15/load-file_test.go
@@ -46,6 +46,7 @@ func TestLoadIacFile(t *testing.T) {
 	table := []struct {
 		name     string
 		filePath string
+		options  map[string]interface{}
 		tfv15    TfV15
 		want     output.AllResourceConfigs
 		wantErr  error
@@ -101,7 +102,7 @@ func TestLoadIacFile(t *testing.T) {
 
 	for _, tt := range table {
 		t.Run(tt.name, func(t *testing.T) {
-			_, gotErr := tt.tfv15.LoadIacFile(tt.filePath)
+			_, gotErr := tt.tfv15.LoadIacFile(tt.filePath, tt.options)
 			if !reflect.DeepEqual(gotErr, tt.wantErr) {
 				t.Errorf("unexpected error; gotErr: '%v', wantErr: '%v'", gotErr, tt.wantErr)
 			}
@@ -112,6 +113,7 @@ func TestLoadIacFile(t *testing.T) {
 		name         string
 		tfConfigFile string
 		tfJSONFile   string
+		options      map[string]interface{}
 		tfv15        TfV15
 		wantErr      error
 	}{
@@ -133,7 +135,7 @@ func TestLoadIacFile(t *testing.T) {
 
 	for _, tt := range table2 {
 		t.Run(tt.name, func(t *testing.T) {
-			got, gotErr := tt.tfv15.LoadIacFile(tt.tfConfigFile)
+			got, gotErr := tt.tfv15.LoadIacFile(tt.tfConfigFile, tt.options)
 			if !reflect.DeepEqual(gotErr, tt.wantErr) {
 				t.Errorf("unexpected error; gotErr: '%v', wantErr: '%v'", gotErr, tt.wantErr)
 			}
diff --git a/pkg/iac-providers/tfplan/v1/load-dir_test.go b/pkg/iac-providers/tfplan/v1/load-dir_test.go
index 147a24e29..abd347a99 100644
--- a/pkg/iac-providers/tfplan/v1/load-dir_test.go
+++ b/pkg/iac-providers/tfplan/v1/load-dir_test.go
@@ -28,8 +28,9 @@ func TestLoadIacDir(t *testing.T) {
 			dirPath = "some-path"
 			tfplan  = TFPlan{}
 			wantErr = errIacDirNotSupport
+			options = make(map[string]interface{})
 		)
-		_, err := tfplan.LoadIacDir(dirPath, false)
+		_, err := tfplan.LoadIacDir(dirPath, options)
 		if !reflect.DeepEqual(wantErr, err) {
 			t.Errorf("error want: '%v', got: '%v'", wantErr, err)
 		}
diff --git a/pkg/iac-providers/tfplan/v1/load-file_test.go b/pkg/iac-providers/tfplan/v1/load-file_test.go
index ffb720626..43d109293 100644
--- a/pkg/iac-providers/tfplan/v1/load-file_test.go
+++ b/pkg/iac-providers/tfplan/v1/load-file_test.go
@@ -38,6 +38,7 @@ func TestLoadIacFile(t *testing.T) {
 	table := []struct {
 		name     string
 		filePath string
+		options  map[string]interface{}
 		tfplan   TFPlan
 		want     output.AllResourceConfigs
 		wantErr  error
@@ -70,13 +71,13 @@ func TestLoadIacFile(t *testing.T) {
 
 	for _, tt := range table {
 		t.Run(tt.name, func(t *testing.T) {
-			_, gotErr := tt.tfplan.LoadIacFile(tt.filePath)
+			_, gotErr := tt.tfplan.LoadIacFile(tt.filePath, tt.options)
 			if !reflect.DeepEqual(gotErr, tt.wantErr) {
 				t.Errorf("unexpected error; gotErr: '%v', wantErr: '%v'", gotErr, tt.wantErr)
 			}
 		})
 	}
-
+	options := make(map[string]interface{})
 	t.Run("validate tfplan iac output", func(t *testing.T) {
 		var (
 			tfplan             = TFPlan{}
@@ -85,7 +86,7 @@ func TestLoadIacFile(t *testing.T) {
 			wantErr      error = nil
 		)
 
-		got, err := tfplan.LoadIacFile(tfplanFile)
+		got, err := tfplan.LoadIacFile(tfplanFile, options)
 		if !reflect.DeepEqual(err, wantErr) {
 			t.Errorf("error want: '%v', got: '%v'", wantErr, err)
 		}
diff --git a/pkg/runtime/executor_test.go b/pkg/runtime/executor_test.go
index 4cc9cd6dd..dc1ba320e 100644
--- a/pkg/runtime/executor_test.go
+++ b/pkg/runtime/executor_test.go
@@ -59,11 +59,11 @@ type MockIacProvider struct {
 	err    error
 }
 
-func (m MockIacProvider) LoadIacDir(dir string, nonRecursive bool) (output.AllResourceConfigs, error) {
+func (m MockIacProvider) LoadIacDir(dir string, options map[string]interface{}) (output.AllResourceConfigs, error) {
 	return m.output, m.err
 }
 
-func (m MockIacProvider) LoadIacFile(file string) (output.AllResourceConfigs, error) {
+func (m MockIacProvider) LoadIacFile(file string, options map[string]interface{}) (output.AllResourceConfigs, error) {
 	return m.output, m.err
 }
 
@@ -557,7 +557,7 @@ func TestNewExecutor(t *testing.T) {
 		t.Run(tt.name, func(t *testing.T) {
 			config.LoadGlobalConfig(tt.configfile)
 
-			gotExecutor, gotErr := NewExecutor(tt.flags.iacType, tt.flags.iacVersion, tt.flags.policyTypes, tt.flags.filePath, tt.flags.dirPath, tt.flags.policyPath, tt.flags.scanRules, tt.flags.skipRules, tt.flags.categories, tt.flags.severity, false)
+			gotExecutor, gotErr := NewExecutor(tt.flags.iacType, tt.flags.iacVersion, tt.flags.policyTypes, tt.flags.filePath, tt.flags.dirPath, tt.flags.policyPath, tt.flags.scanRules, tt.flags.skipRules, tt.flags.categories, tt.flags.severity, false, false)
 
 			if !reflect.DeepEqual(tt.wantErr, gotErr) {
 				t.Errorf("Mismatch in error => got: '%v', want: '%v'", gotErr, tt.wantErr)
diff --git a/test/e2e/help/golden/help_scan.txt b/test/e2e/help/golden/help_scan.txt
index 7c2d00d55..8b444d480 100644
--- a/test/e2e/help/golden/help_scan.txt
+++ b/test/e2e/help/golden/help_scan.txt
@@ -15,7 +15,7 @@ Flags:
       --iac-version string        iac version (arm: v1, cft: v1, docker: v1, helm: v3, k8s: v1, kustomize: v3, terraform: v12, v13, v14, v15, tfplan: v1)
       --non-recursive             do not scan directories and modules recursively
   -p, --policy-path stringArray   policy path directory
-  -t, --policy-type strings       policy type (all, aws, azure, gcp, github, k8s) (default [all])
+  -t, --policy-type strings       policy type (all, aws, azure, docker, gcp, github, k8s) (default [all])
   -r, --remote-type string        type of remote backend (git, s3, gcs, http, terraform-registry)
   -u, --remote-url string         url pointing to remote IaC repository
       --scan-rules strings        one or more rules to scan (example: --scan-rules="ruleID1,ruleID2")
@@ -23,6 +23,7 @@ Flags:
       --show-passed               display passed rules, along with violations
       --skip-rules strings        one or more rules to skip while scanning (example: --skip-rules="ruleID1,ruleID2")
       --use-colors string         color output (auto, t, f) (default "auto")
+      --use-terraform-cache       use terraform init cache for remote modules (when used directory scan will be non recursive, flag applicable only with terraform IaC provider)
   -v, --verbose                   will show violations with details (applicable for default output)
 
 Global Flags:
diff --git a/test/e2e/scan/golden/terraform_scans/terraform_cache_use_in_scan/terraform_cache_use_in_scan_result.txt b/test/e2e/scan/golden/terraform_scans/terraform_cache_use_in_scan/terraform_cache_use_in_scan_result.txt
new file mode 100644
index 000000000..660333c01
--- /dev/null
+++ b/test/e2e/scan/golden/terraform_scans/terraform_cache_use_in_scan/terraform_cache_use_in_scan_result.txt
@@ -0,0 +1,16 @@
+{
+  "results": {
+    "violations": null,
+    "skipped_violations": null,
+    "scan_summary": {
+      "file/folder": "/Users/suvarna/go/src/github.com/rchanger/terrascan/test/e2e/test_data/iac/terraform_cache_use_in_scan",
+      "iac_type": "terraform",
+      "scanned_at": "2021-07-22 16:06:39.189999 +0000 UTC",
+      "policies_validated": 8,
+      "violated_policies": 0,
+      "low": 0,
+      "medium": 0,
+      "high": 0
+    }
+  }
+}
\ No newline at end of file
diff --git a/test/e2e/scan/scan_tf_files_test.go b/test/e2e/scan/scan_tf_files_test.go
index 1eba8579e..8589670cd 100644
--- a/test/e2e/scan/scan_tf_files_test.go
+++ b/test/e2e/scan/scan_tf_files_test.go
@@ -17,9 +17,10 @@
 package scan_test
 
 import (
-	"github.com/accurics/terrascan/pkg/version"
 	"path/filepath"
 
+	"github.com/accurics/terrascan/pkg/version"
+
 	scanUtils "github.com/accurics/terrascan/test/e2e/scan"
 	"github.com/accurics/terrascan/test/helper"
 	. "github.com/onsi/ginkgo"
@@ -224,5 +225,14 @@ var _ = Describe("Scan is run for terraform files", func() {
 				})
 			})
 		})
+		Context("when --use-terraform-cache flag is used, all remote modules are refered from terraform cache", func() {
+			When("when --use-terraform-cache is set with output format json", func() {
+				It("should not display any violations", func() {
+					iacDir := filepath.Join(iacRootRelPath, "terraform_cache_use_in_scan")
+					scanArgs := []string{"-i", "terraform", "-p", policyDir, "-d", iacDir, "-o", "json", "--use-terraform-cache"}
+					scanUtils.RunScanAndAssertGoldenOutputRegex(terrascanBinaryPath, filepath.Join(tfGoldenRelPath, "terraform_cache_use_in_scan", "terraform_cache_use_in_scan_result.txt"), helper.ExitCodeZero, false, true, outWriter, errWriter, scanArgs...)
+				})
+			})
+		})
 	})
 })
diff --git a/test/e2e/test_data/iac/terraform_cache_use_in_scan/.terraform/modules/modules.json b/test/e2e/test_data/iac/terraform_cache_use_in_scan/.terraform/modules/modules.json
new file mode 100644
index 000000000..3f3723ed3
--- /dev/null
+++ b/test/e2e/test_data/iac/terraform_cache_use_in_scan/.terraform/modules/modules.json
@@ -0,0 +1,15 @@
+{
+    "Modules": [
+        {
+            "Key": "",
+            "Source": "",
+            "Dir": "."
+        },
+        {
+            "Key": "network",
+            "Source": "Azure/network/azurerm",
+            "Version": "3.2.1",
+            "Dir": ".terraform/modules/network"
+        }
+    ]
+}
\ No newline at end of file
diff --git a/test/e2e/test_data/iac/terraform_cache_use_in_scan/.terraform/modules/network/main.tf b/test/e2e/test_data/iac/terraform_cache_use_in_scan/.terraform/modules/network/main.tf
new file mode 100644
index 000000000..780f2118c
--- /dev/null
+++ b/test/e2e/test_data/iac/terraform_cache_use_in_scan/.terraform/modules/network/main.tf
@@ -0,0 +1,21 @@
+#Azure Generic vNet Module
+data "azurerm_resource_group" "network" {
+  name = var.resource_group_name
+}
+
+resource "azurerm_virtual_network" "vnet" {
+  name                = var.vnet_name
+  resource_group_name = data.azurerm_resource_group.network.name
+  location            = data.azurerm_resource_group.network.location
+  address_space       = [var.address_space]
+  dns_servers         = var.dns_servers
+  tags                = var.tags
+}
+
+resource "azurerm_subnet" "subnet" {
+  count                = length(var.subnet_names)
+  name                 = var.subnet_names[count.index]
+  resource_group_name  = data.azurerm_resource_group.network.name
+  address_prefixes     = [var.subnet_prefixes[count.index]]
+  virtual_network_name = azurerm_virtual_network.vnet.name
+}
diff --git a/test/e2e/test_data/iac/terraform_cache_use_in_scan/.terraform/modules/network/outputs.tf b/test/e2e/test_data/iac/terraform_cache_use_in_scan/.terraform/modules/network/outputs.tf
new file mode 100644
index 000000000..4534e0215
--- /dev/null
+++ b/test/e2e/test_data/iac/terraform_cache_use_in_scan/.terraform/modules/network/outputs.tf
@@ -0,0 +1,24 @@
+output "vnet_id" {
+  description = "The id of the newly created vNet"
+  value       = azurerm_virtual_network.vnet.id
+}
+
+output "vnet_name" {
+  description = "The Name of the newly created vNet"
+  value       = azurerm_virtual_network.vnet.name
+}
+
+output "vnet_location" {
+  description = "The location of the newly created vNet"
+  value       = azurerm_virtual_network.vnet.location
+}
+
+output "vnet_address_space" {
+  description = "The address space of the newly created vNet"
+  value       = azurerm_virtual_network.vnet.address_space
+}
+
+output "vnet_subnets" {
+  description = "The ids of subnets created inside the newl vNet"
+  value       = azurerm_subnet.subnet.*.id
+}
diff --git a/test/e2e/test_data/iac/terraform_cache_use_in_scan/.terraform/modules/network/variables.tf b/test/e2e/test_data/iac/terraform_cache_use_in_scan/.terraform/modules/network/variables.tf
new file mode 100644
index 000000000..3a964abf9
--- /dev/null
+++ b/test/e2e/test_data/iac/terraform_cache_use_in_scan/.terraform/modules/network/variables.tf
@@ -0,0 +1,44 @@
+variable "vnet_name" {
+  description = "Name of the vnet to create."
+  type        = string
+  default     = "acctvnet"
+}
+
+variable "resource_group_name" {
+  description = "The name of an existing resource group to be imported."
+  type        = string
+}
+
+variable "address_space" {
+  description = "The address space that is used by the virtual network."
+  type        = string
+  default     = "10.0.0.0/16"
+}
+
+# If no values specified, this defaults to Azure DNS 
+variable "dns_servers" {
+  description = "The DNS servers to be used with vNet."
+  type        = list(string)
+  default     = []
+}
+
+variable "subnet_prefixes" {
+  description = "The address prefix to use for the subnet."
+  type        = list(string)
+  default     = ["10.0.1.0/24"]
+}
+
+variable "subnet_names" {
+  description = "A list of public subnets inside the vNet."
+  type        = list(string)
+  default     = ["subnet1"]
+}
+
+variable "tags" {
+  description = "The tags to associate with your network and subnets."
+  type        = map(string)
+
+  default = {
+    environment = "dev"
+  }
+}
diff --git a/test/e2e/test_data/iac/terraform_cache_use_in_scan/remote-module.tf b/test/e2e/test_data/iac/terraform_cache_use_in_scan/remote-module.tf
new file mode 100644
index 000000000..fb88de2fd
--- /dev/null
+++ b/test/e2e/test_data/iac/terraform_cache_use_in_scan/remote-module.tf
@@ -0,0 +1,9 @@
+#file added for fix for #418
+
+# source https://registry.terraform.io/
+
+module "network" {
+  source  = "Azure/network/azurerm"
+  version = "3.2.1"
+}
+