github.com/khulnasoft-lab/defsec@v1.0.5-0.20230827010352-5e9f46893d95/internal/adapters/terraform/azure/storage/adapt.go (about)

     1  package storage
     2  
     3  import (
     4  	defsecTypes "github.com/khulnasoft-lab/defsec/pkg/types"
     5  
     6  	"github.com/khulnasoft-lab/defsec/pkg/providers/azure/storage"
     7  	"github.com/khulnasoft-lab/defsec/pkg/terraform"
     8  )
     9  
    10  func Adapt(modules terraform.Modules) storage.Storage {
    11  	accounts, containers, networkRules := adaptAccounts(modules)
    12  
    13  	orphanAccount := storage.Account{
    14  		Metadata:     defsecTypes.NewUnmanagedMetadata(),
    15  		NetworkRules: adaptOrphanNetworkRules(modules, networkRules),
    16  		EnforceHTTPS: defsecTypes.BoolDefault(false, defsecTypes.NewUnmanagedMetadata()),
    17  		Containers:   adaptOrphanContainers(modules, containers),
    18  		QueueProperties: storage.QueueProperties{
    19  			Metadata:      defsecTypes.NewUnmanagedMetadata(),
    20  			EnableLogging: defsecTypes.BoolDefault(false, defsecTypes.NewUnmanagedMetadata()),
    21  		},
    22  		MinimumTLSVersion: defsecTypes.StringDefault("", defsecTypes.NewUnmanagedMetadata()),
    23  	}
    24  
    25  	accounts = append(accounts, orphanAccount)
    26  
    27  	return storage.Storage{
    28  		Accounts: accounts,
    29  	}
    30  }
    31  
    32  func adaptOrphanContainers(modules terraform.Modules, containers []string) (orphans []storage.Container) {
    33  	accountedFor := make(map[string]bool)
    34  	for _, container := range containers {
    35  		accountedFor[container] = true
    36  	}
    37  	for _, module := range modules {
    38  		for _, containerResource := range module.GetResourcesByType("azurerm_storage_container") {
    39  			if _, ok := accountedFor[containerResource.ID()]; ok {
    40  				continue
    41  			}
    42  			orphans = append(orphans, adaptContainer(containerResource))
    43  		}
    44  	}
    45  
    46  	return orphans
    47  }
    48  
    49  func adaptOrphanNetworkRules(modules terraform.Modules, networkRules []string) (orphans []storage.NetworkRule) {
    50  	accountedFor := make(map[string]bool)
    51  	for _, networkRule := range networkRules {
    52  		accountedFor[networkRule] = true
    53  	}
    54  
    55  	for _, module := range modules {
    56  		for _, networkRuleResource := range module.GetResourcesByType("azurerm_storage_account_network_rules") {
    57  			if _, ok := accountedFor[networkRuleResource.ID()]; ok {
    58  				continue
    59  			}
    60  
    61  			orphans = append(orphans, adaptNetworkRule(networkRuleResource))
    62  		}
    63  	}
    64  
    65  	return orphans
    66  }
    67  
    68  func adaptAccounts(modules terraform.Modules) ([]storage.Account, []string, []string) {
    69  	var accounts []storage.Account
    70  	var accountedForContainers []string
    71  	var accountedForNetworkRules []string
    72  
    73  	for _, module := range modules {
    74  		for _, resource := range module.GetResourcesByType("azurerm_storage_account") {
    75  			account := adaptAccount(resource)
    76  			containerResource := module.GetReferencingResources(resource, "azurerm_storage_container", "storage_account_name")
    77  			for _, containerBlock := range containerResource {
    78  				accountedForContainers = append(accountedForContainers, containerBlock.ID())
    79  				account.Containers = append(account.Containers, adaptContainer(containerBlock))
    80  			}
    81  			networkRulesResource := module.GetReferencingResources(resource, "azurerm_storage_account_network_rules", "storage_account_name")
    82  			for _, networkRuleBlock := range networkRulesResource {
    83  				accountedForNetworkRules = append(accountedForNetworkRules, networkRuleBlock.ID())
    84  				account.NetworkRules = append(account.NetworkRules, adaptNetworkRule(networkRuleBlock))
    85  			}
    86  			for _, queueBlock := range module.GetReferencingResources(resource, "azurerm_storage_queue", "storage_account_name") {
    87  				queue := storage.Queue{
    88  					Metadata: queueBlock.GetMetadata(),
    89  					Name:     queueBlock.GetAttribute("name").AsStringValueOrDefault("", queueBlock),
    90  				}
    91  				account.Queues = append(account.Queues, queue)
    92  			}
    93  			accounts = append(accounts, account)
    94  		}
    95  	}
    96  
    97  	return accounts, accountedForContainers, accountedForNetworkRules
    98  }
    99  
   100  func adaptAccount(resource *terraform.Block) storage.Account {
   101  	account := storage.Account{
   102  		Metadata:     resource.GetMetadata(),
   103  		NetworkRules: nil,
   104  		EnforceHTTPS: defsecTypes.BoolDefault(true, resource.GetMetadata()),
   105  		Containers:   nil,
   106  		QueueProperties: storage.QueueProperties{
   107  			Metadata:      resource.GetMetadata(),
   108  			EnableLogging: defsecTypes.BoolDefault(false, resource.GetMetadata()),
   109  		},
   110  		MinimumTLSVersion: defsecTypes.StringDefault("TLS1_2", resource.GetMetadata()),
   111  	}
   112  
   113  	networkRulesBlocks := resource.GetBlocks("network_rules")
   114  	for _, networkBlock := range networkRulesBlocks {
   115  		account.NetworkRules = append(account.NetworkRules, adaptNetworkRule(networkBlock))
   116  	}
   117  
   118  	httpsOnlyAttr := resource.GetAttribute("enable_https_traffic_only")
   119  	account.EnforceHTTPS = httpsOnlyAttr.AsBoolValueOrDefault(true, resource)
   120  
   121  	queuePropertiesBlock := resource.GetBlock("queue_properties")
   122  	if queuePropertiesBlock.IsNotNil() {
   123  		account.QueueProperties.Metadata = queuePropertiesBlock.GetMetadata()
   124  		loggingBlock := queuePropertiesBlock.GetBlock("logging")
   125  		if loggingBlock.IsNotNil() {
   126  			account.QueueProperties.EnableLogging = defsecTypes.Bool(true, loggingBlock.GetMetadata())
   127  		}
   128  	}
   129  
   130  	minTLSVersionAttr := resource.GetAttribute("min_tls_version")
   131  	account.MinimumTLSVersion = minTLSVersionAttr.AsStringValueOrDefault("TLS1_0", resource)
   132  	return account
   133  }
   134  
   135  func adaptContainer(resource *terraform.Block) storage.Container {
   136  	accessTypeAttr := resource.GetAttribute("container_access_type")
   137  	publicAccess := defsecTypes.StringDefault(storage.PublicAccessOff, resource.GetMetadata())
   138  
   139  	if accessTypeAttr.Equals("blob") {
   140  		publicAccess = defsecTypes.String(storage.PublicAccessBlob, accessTypeAttr.GetMetadata())
   141  	} else if accessTypeAttr.Equals("container") {
   142  		publicAccess = defsecTypes.String(storage.PublicAccessContainer, accessTypeAttr.GetMetadata())
   143  	}
   144  
   145  	return storage.Container{
   146  		Metadata:     resource.GetMetadata(),
   147  		PublicAccess: publicAccess,
   148  	}
   149  }
   150  
   151  func adaptNetworkRule(resource *terraform.Block) storage.NetworkRule {
   152  	var allowByDefault defsecTypes.BoolValue
   153  	var bypass []defsecTypes.StringValue
   154  
   155  	defaultActionAttr := resource.GetAttribute("default_action")
   156  
   157  	if defaultActionAttr.IsNotNil() {
   158  		allowByDefault = defsecTypes.Bool(defaultActionAttr.Equals("Allow", terraform.IgnoreCase), defaultActionAttr.GetMetadata())
   159  	} else {
   160  		allowByDefault = defsecTypes.BoolDefault(false, resource.GetMetadata())
   161  	}
   162  
   163  	if resource.HasChild("bypass") {
   164  		bypassAttr := resource.GetAttribute("bypass")
   165  		bypass = bypassAttr.AsStringValues()
   166  	}
   167  
   168  	return storage.NetworkRule{
   169  		Metadata:       resource.GetMetadata(),
   170  		Bypass:         bypass,
   171  		AllowByDefault: allowByDefault,
   172  	}
   173  }