github.com/khulnasoft-lab/defsec@v1.0.5-0.20230827010352-5e9f46893d95/internal/adapters/terraform/aws/s3/bucket.go (about)

     1  package s3
     2  
     3  import (
     4  	"github.com/khulnasoft-lab/defsec/pkg/providers/aws/s3"
     5  	"github.com/khulnasoft-lab/defsec/pkg/terraform"
     6  	defsecTypes "github.com/khulnasoft-lab/defsec/pkg/types"
     7  )
     8  
     9  type adapter struct {
    10  	modules   terraform.Modules
    11  	bucketMap map[string]*s3.Bucket
    12  }
    13  
    14  func (a *adapter) adaptBuckets() []s3.Bucket {
    15  	for _, block := range a.modules.GetResourcesByType("aws_s3_bucket") {
    16  		bucket := &s3.Bucket{
    17  			Metadata:                      block.GetMetadata(),
    18  			Name:                          block.GetAttribute("bucket").AsStringValueOrDefault("", block),
    19  			PublicAccessBlock:             nil,
    20  			BucketPolicies:                nil,
    21  			Encryption:                    getEncryption(block, a),
    22  			Versioning:                    getVersioning(block, a),
    23  			Logging:                       getLogging(block, a),
    24  			ACL:                           getBucketAcl(block, a),
    25  			AccelerateConfigurationStatus: getaccelerateStatus(block, a),
    26  			BucketLocation:                block.GetAttribute("region").AsStringValueOrDefault("", block),
    27  			LifecycleConfiguration:        getLifecycle(block, a),
    28  			Website:                       getWebsite(block, a),
    29  			Objects:                       getObject(block, a),
    30  		}
    31  		a.bucketMap[block.ID()] = bucket
    32  	}
    33  
    34  	a.adaptBucketPolicies()
    35  	a.adaptPublicAccessBlocks()
    36  
    37  	var buckets []s3.Bucket
    38  	for _, bucket := range a.bucketMap {
    39  		buckets = append(buckets, *bucket)
    40  	}
    41  
    42  	return buckets
    43  }
    44  
    45  func getEncryption(block *terraform.Block, a *adapter) s3.Encryption {
    46  	if block.HasChild("server_side_encryption_configuration") {
    47  		return s3.Encryption{
    48  			Metadata:  block.GetMetadata(),
    49  			Enabled:   isEncrypted(block.GetBlock("server_side_encryption_configuration")),
    50  			Algorithm: block.GetNestedAttribute("server_side_encryption_configuration.rule.apply_server_side_encryption_by_default.sse_algorithm").AsStringValueOrDefault("", block),
    51  			KMSKeyId:  block.GetNestedAttribute("server_side_encryption_configuration.rule.apply_server_side_encryption_by_default.kms_master_key_id").AsStringValueOrDefault("", block),
    52  		}
    53  	}
    54  	if val, ok := applyForBucketRelatedResource(a, block, "aws_s3_bucket_server_side_encryption_configuration", func(resource *terraform.Block) s3.Encryption {
    55  		return s3.Encryption{
    56  			Metadata:  resource.GetMetadata(),
    57  			Enabled:   isEncrypted(resource),
    58  			Algorithm: resource.GetNestedAttribute("rule.apply_server_side_encryption_by_default.sse_algorithm").AsStringValueOrDefault("", block),
    59  			KMSKeyId:  resource.GetNestedAttribute("rule.apply_server_side_encryption_by_default.kms_master_key_id").AsStringValueOrDefault("", block),
    60  		}
    61  	}); ok {
    62  		return val
    63  	}
    64  	return s3.Encryption{
    65  		Metadata:  block.GetMetadata(),
    66  		Enabled:   defsecTypes.BoolDefault(false, block.GetMetadata()),
    67  		KMSKeyId:  defsecTypes.StringDefault("", block.GetMetadata()),
    68  		Algorithm: defsecTypes.StringDefault("", block.GetMetadata()),
    69  	}
    70  }
    71  
    72  func getVersioning(block *terraform.Block, a *adapter) s3.Versioning {
    73  	versioning := s3.Versioning{
    74  		Metadata:  block.GetMetadata(),
    75  		Enabled:   defsecTypes.BoolDefault(false, block.GetMetadata()),
    76  		MFADelete: defsecTypes.BoolDefault(false, block.GetMetadata()),
    77  	}
    78  	if lockBlock := block.GetBlock("object_lock_configuration"); lockBlock != nil {
    79  		if enabled := isObjeckLockEnabled(lockBlock); enabled != nil {
    80  			versioning.Enabled = *enabled
    81  		}
    82  	}
    83  	if vBlock := block.GetBlock("versioning"); vBlock != nil {
    84  		versioning.Enabled = vBlock.GetAttribute("enabled").AsBoolValueOrDefault(true, vBlock)
    85  		versioning.MFADelete = vBlock.GetAttribute("mfa_delete").AsBoolValueOrDefault(false, vBlock)
    86  	}
    87  
    88  	if enabled, ok := applyForBucketRelatedResource(a, block, "aws_s3_bucket_object_lock_configuration", func(resource *terraform.Block) *defsecTypes.BoolValue {
    89  		if block.GetAttribute("object_lock_enabled").IsTrue() {
    90  			return isObjeckLockEnabled(resource)
    91  		}
    92  		return nil
    93  	}); ok && enabled != nil {
    94  		versioning.Enabled = *enabled
    95  	}
    96  
    97  	if val, ok := applyForBucketRelatedResource(a, block, "aws_s3_bucket_versioning", getVersioningFromResource); ok {
    98  		return val
    99  	}
   100  	return versioning
   101  }
   102  
   103  func isObjeckLockEnabled(resource *terraform.Block) *defsecTypes.BoolValue {
   104  	var val defsecTypes.BoolValue
   105  	attr := resource.GetAttribute("object_lock_enabled")
   106  	switch {
   107  	case attr.IsNil(): // enabled by default
   108  		val = defsecTypes.BoolDefault(true, resource.GetMetadata())
   109  	case attr.Equals("Enabled"):
   110  		val = defsecTypes.Bool(true, attr.GetMetadata())
   111  	}
   112  	return &val
   113  }
   114  
   115  // from aws_s3_bucket_versioning
   116  func getVersioningFromResource(block *terraform.Block) s3.Versioning {
   117  	versioning := s3.Versioning{
   118  		Metadata:  block.GetMetadata(),
   119  		Enabled:   defsecTypes.BoolDefault(false, block.GetMetadata()),
   120  		MFADelete: defsecTypes.BoolDefault(false, block.GetMetadata()),
   121  	}
   122  	if config := block.GetBlock("versioning_configuration"); config != nil {
   123  		if status := config.GetAttribute("status"); status.IsNotNil() {
   124  			versioning.Enabled = defsecTypes.Bool(status.Equals("Enabled", terraform.IgnoreCase), status.GetMetadata())
   125  		}
   126  		if mfa := config.GetAttribute("mfa_delete"); mfa.IsNotNil() {
   127  			versioning.MFADelete = defsecTypes.Bool(mfa.Equals("Enabled", terraform.IgnoreCase), mfa.GetMetadata())
   128  		}
   129  	}
   130  	return versioning
   131  }
   132  
   133  func getLogging(block *terraform.Block, a *adapter) s3.Logging {
   134  	if loggingBlock := block.GetBlock("logging"); loggingBlock.IsNotNil() {
   135  		targetBucket := loggingBlock.GetAttribute("target_bucket").AsStringValueOrDefault("", loggingBlock)
   136  		if referencedBlock, err := a.modules.GetReferencedBlock(loggingBlock.GetAttribute("target_bucket"), loggingBlock); err == nil {
   137  			targetBucket = defsecTypes.String(referencedBlock.FullName(), loggingBlock.GetAttribute("target_bucket").GetMetadata())
   138  		}
   139  		return s3.Logging{
   140  			Metadata:     loggingBlock.GetMetadata(),
   141  			Enabled:      defsecTypes.Bool(true, loggingBlock.GetMetadata()),
   142  			TargetBucket: targetBucket,
   143  		}
   144  	}
   145  
   146  	if val, ok := applyForBucketRelatedResource(a, block, "aws_s3_bucket_logging", func(resource *terraform.Block) s3.Logging {
   147  		targetBucket := resource.GetAttribute("target-bucket").AsStringValueOrDefault("", resource)
   148  		if referencedBlock, err := a.modules.GetReferencedBlock(resource.GetAttribute("target_bucket"), resource); err == nil {
   149  			targetBucket = defsecTypes.String(referencedBlock.FullName(), resource.GetAttribute("target_bucket").GetMetadata())
   150  		}
   151  		return s3.Logging{
   152  			Metadata:     resource.GetMetadata(),
   153  			Enabled:      hasLogging(resource),
   154  			TargetBucket: targetBucket,
   155  		}
   156  	}); ok {
   157  		return val
   158  	}
   159  
   160  	return s3.Logging{
   161  		Metadata:     block.GetMetadata(),
   162  		Enabled:      defsecTypes.Bool(false, block.GetMetadata()),
   163  		TargetBucket: defsecTypes.StringDefault("", block.GetMetadata()),
   164  	}
   165  }
   166  
   167  func getBucketAcl(block *terraform.Block, a *adapter) defsecTypes.StringValue {
   168  	aclAttr := block.GetAttribute("acl")
   169  	if aclAttr.IsString() {
   170  		return aclAttr.AsStringValueOrDefault("private", block)
   171  	}
   172  
   173  	if val, ok := applyForBucketRelatedResource(a, block, "aws_s3_bucket_acl", func(resource *terraform.Block) defsecTypes.StringValue {
   174  		return resource.GetAttribute("acl").AsStringValueOrDefault("private", resource)
   175  	}); ok {
   176  		return val
   177  	}
   178  	return defsecTypes.StringDefault("private", block.GetMetadata())
   179  }
   180  
   181  func isEncrypted(encryptionBlock *terraform.Block) defsecTypes.BoolValue {
   182  	ruleBlock := encryptionBlock.GetBlock("rule")
   183  	if ruleBlock.IsNil() {
   184  		return defsecTypes.BoolDefault(false, encryptionBlock.GetMetadata())
   185  	}
   186  	defaultBlock := ruleBlock.GetBlock("apply_server_side_encryption_by_default")
   187  	if defaultBlock.IsNil() {
   188  		return defsecTypes.BoolDefault(false, ruleBlock.GetMetadata())
   189  	}
   190  	sseAlgorithm := defaultBlock.GetAttribute("sse_algorithm")
   191  	if sseAlgorithm.IsNil() {
   192  		return defsecTypes.BoolDefault(false, defaultBlock.GetMetadata())
   193  	}
   194  	return defsecTypes.Bool(
   195  		true,
   196  		sseAlgorithm.GetMetadata(),
   197  	)
   198  }
   199  
   200  func hasLogging(b *terraform.Block) defsecTypes.BoolValue {
   201  	if loggingBlock := b.GetBlock("logging"); loggingBlock.IsNotNil() {
   202  		if targetAttr := loggingBlock.GetAttribute("target_bucket"); targetAttr.IsNotNil() && targetAttr.IsNotEmpty() {
   203  			return defsecTypes.Bool(true, targetAttr.GetMetadata())
   204  		}
   205  		return defsecTypes.BoolDefault(false, loggingBlock.GetMetadata())
   206  	}
   207  	if targetBucket := b.GetAttribute("target_bucket"); targetBucket.IsNotNil() {
   208  		return defsecTypes.Bool(true, targetBucket.GetMetadata())
   209  	}
   210  	return defsecTypes.BoolDefault(false, b.GetMetadata())
   211  }
   212  
   213  func getLifecycle(b *terraform.Block, a *adapter) []s3.Rules {
   214  
   215  	var rules []s3.Rules
   216  	for _, r := range a.modules.GetReferencingResources(b, "aws_s3_bucket_lifecycle_configuration", "bucket") {
   217  		ruleblock := r.GetBlocks("rule")
   218  		for _, rule := range ruleblock {
   219  			rules = append(rules, s3.Rules{
   220  				Metadata: rule.GetMetadata(),
   221  				Status:   rule.GetAttribute("status").AsStringValueOrDefault("Enabled", rule),
   222  			})
   223  		}
   224  	}
   225  	return rules
   226  }
   227  
   228  func getWebsite(b *terraform.Block, a *adapter) (website *s3.Website) {
   229  	for _, r := range a.modules.GetReferencingResources(b, "aws_s3_bucket_website_configuration", "bucket") {
   230  		website = &s3.Website{
   231  			Metadata: r.GetMetadata(),
   232  		}
   233  	}
   234  	return website
   235  }
   236  
   237  func getObject(b *terraform.Block, a *adapter) []s3.Contents {
   238  	var object []s3.Contents
   239  	for _, r := range a.modules.GetReferencingResources(b, "aws_s3_object", "bucket") {
   240  		object = append(object, s3.Contents{
   241  			Metadata: r.GetMetadata(),
   242  		})
   243  	}
   244  	return object
   245  }
   246  
   247  func getaccelerateStatus(b *terraform.Block, a *adapter) defsecTypes.StringValue {
   248  	var status defsecTypes.StringValue
   249  	for _, r := range a.modules.GetReferencingResources(b, " aws_s3_bucket_accelerate_configuration", "bucket") {
   250  		status = r.GetAttribute("status").AsStringValueOrDefault("Enabled", r)
   251  	}
   252  	return status
   253  }
   254  
   255  func applyForBucketRelatedResource[T any](a *adapter, block *terraform.Block, resType string, fn func(resource *terraform.Block) T) (T, bool) {
   256  	for _, resource := range a.modules.GetResourcesByType(resType) {
   257  		bucketAttr := resource.GetAttribute("bucket")
   258  		if bucketAttr.IsNotNil() {
   259  			if bucketAttr.IsString() {
   260  				actualBucketName := block.GetAttribute("bucket").AsStringValueOrDefault("", block).Value()
   261  				if bucketAttr.Equals(block.ID()) || bucketAttr.Equals(actualBucketName) {
   262  					return fn(resource), true
   263  				}
   264  			}
   265  			if referencedBlock, err := a.modules.GetReferencedBlock(bucketAttr, resource); err == nil {
   266  				if referencedBlock.ID() == block.ID() {
   267  					return fn(resource), true
   268  				}
   269  			}
   270  		}
   271  
   272  	}
   273  	var res T
   274  	return res, false
   275  }