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

     1  package s3
     2  
     3  import (
     4  	"regexp"
     5  	"strings"
     6  
     7  	defsecTypes "github.com/khulnasoft-lab/defsec/pkg/types"
     8  
     9  	"github.com/khulnasoft-lab/defsec/pkg/providers/aws/s3"
    10  	"github.com/khulnasoft-lab/defsec/pkg/scanners/cloudformation/parser"
    11  )
    12  
    13  var aclConvertRegex = regexp.MustCompile(`[A-Z][^A-Z]*`)
    14  
    15  func getBuckets(cfFile parser.FileContext) []s3.Bucket {
    16  	var buckets []s3.Bucket
    17  	bucketResources := cfFile.GetResourcesByType("AWS::S3::Bucket")
    18  
    19  	for _, r := range bucketResources {
    20  		s3b := s3.Bucket{
    21  			Metadata:          r.Metadata(),
    22  			Name:              r.GetStringProperty("BucketName"),
    23  			PublicAccessBlock: getPublicAccessBlock(r),
    24  			Encryption:        getEncryption(r, cfFile),
    25  			Versioning: s3.Versioning{
    26  				Metadata:  r.Metadata(),
    27  				Enabled:   hasVersioning(r),
    28  				MFADelete: defsecTypes.BoolUnresolvable(r.Metadata()),
    29  			},
    30  			Logging:                       getLogging(r),
    31  			ACL:                           convertAclValue(r.GetStringProperty("AccessControl", "private")),
    32  			LifecycleConfiguration:        getLifecycle(r),
    33  			AccelerateConfigurationStatus: r.GetStringProperty("AccelerateConfiguration.AccelerationStatus"),
    34  			Website:                       getWebsite(r),
    35  			BucketLocation:                defsecTypes.String("", r.Metadata()),
    36  			Objects:                       nil,
    37  		}
    38  
    39  		buckets = append(buckets, s3b)
    40  	}
    41  	return buckets
    42  }
    43  
    44  func getPublicAccessBlock(r *parser.Resource) *s3.PublicAccessBlock {
    45  	if block := r.GetProperty("PublicAccessBlockConfiguration"); block.IsNil() {
    46  		return nil
    47  	}
    48  
    49  	return &s3.PublicAccessBlock{
    50  		Metadata:              r.Metadata(),
    51  		BlockPublicACLs:       r.GetBoolProperty("PublicAccessBlockConfiguration.BlockPublicAcls"),
    52  		BlockPublicPolicy:     r.GetBoolProperty("PublicAccessBlockConfiguration.BlockPublicPolicy"),
    53  		IgnorePublicACLs:      r.GetBoolProperty("PublicAccessBlockConfiguration.IgnorePublicAcls"),
    54  		RestrictPublicBuckets: r.GetBoolProperty("PublicAccessBlockConfiguration.RestrictPublicBuckets"),
    55  	}
    56  }
    57  
    58  func convertAclValue(aclValue defsecTypes.StringValue) defsecTypes.StringValue {
    59  	matches := aclConvertRegex.FindAllString(aclValue.Value(), -1)
    60  
    61  	return defsecTypes.String(strings.ToLower(strings.Join(matches, "-")), aclValue.GetMetadata())
    62  }
    63  
    64  func getLogging(r *parser.Resource) s3.Logging {
    65  
    66  	logging := s3.Logging{
    67  		Metadata:     r.Metadata(),
    68  		Enabled:      defsecTypes.BoolDefault(false, r.Metadata()),
    69  		TargetBucket: defsecTypes.StringDefault("", r.Metadata()),
    70  	}
    71  
    72  	if config := r.GetProperty("LoggingConfiguration"); config.IsNotNil() {
    73  		logging.TargetBucket = config.GetStringProperty("DestinationBucketName")
    74  		if logging.TargetBucket.IsNotEmpty() || !logging.TargetBucket.GetMetadata().IsResolvable() {
    75  			logging.Enabled = defsecTypes.Bool(true, config.Metadata())
    76  		}
    77  	}
    78  	return logging
    79  }
    80  
    81  func hasVersioning(r *parser.Resource) defsecTypes.BoolValue {
    82  	versioningProp := r.GetProperty("VersioningConfiguration.Status")
    83  
    84  	if versioningProp.IsNil() {
    85  		return defsecTypes.BoolDefault(false, r.Metadata())
    86  	}
    87  
    88  	versioningEnabled := false
    89  	if versioningProp.EqualTo("Enabled") {
    90  		versioningEnabled = true
    91  
    92  	}
    93  	return defsecTypes.Bool(versioningEnabled, versioningProp.Metadata())
    94  }
    95  
    96  func getEncryption(r *parser.Resource, _ parser.FileContext) s3.Encryption {
    97  
    98  	encryption := s3.Encryption{
    99  		Metadata:  r.Metadata(),
   100  		Enabled:   defsecTypes.BoolDefault(false, r.Metadata()),
   101  		Algorithm: defsecTypes.StringDefault("", r.Metadata()),
   102  		KMSKeyId:  defsecTypes.StringDefault("", r.Metadata()),
   103  	}
   104  
   105  	if encryptProps := r.GetProperty("BucketEncryption.ServerSideEncryptionConfiguration"); encryptProps.IsNotNil() {
   106  		for _, rule := range encryptProps.AsList() {
   107  			if algo := rule.GetProperty("ServerSideEncryptionByDefault.SSEAlgorithm"); algo.EqualTo("AES256") {
   108  				encryption.Enabled = defsecTypes.Bool(true, algo.Metadata())
   109  			} else if kmsKeyProp := rule.GetProperty("ServerSideEncryptionByDefault.KMSMasterKeyID"); !kmsKeyProp.IsEmpty() && kmsKeyProp.IsString() {
   110  				encryption.KMSKeyId = kmsKeyProp.AsStringValue()
   111  			}
   112  			if encryption.Enabled.IsFalse() {
   113  				encryption.Enabled = rule.GetBoolProperty("BucketKeyEnabled", false)
   114  			}
   115  		}
   116  	}
   117  
   118  	return encryption
   119  }
   120  
   121  func getLifecycle(resource *parser.Resource) []s3.Rules {
   122  	LifecycleProp := resource.GetProperty("LifecycleConfiguration")
   123  	RuleProp := LifecycleProp.GetProperty("Rules")
   124  
   125  	var rule []s3.Rules
   126  
   127  	if RuleProp.IsNil() || RuleProp.IsNotList() {
   128  		return rule
   129  	}
   130  
   131  	for _, r := range RuleProp.AsList() {
   132  		rule = append(rule, s3.Rules{
   133  			Metadata: r.Metadata(),
   134  			Status:   r.GetStringProperty("Status"),
   135  		})
   136  	}
   137  	return rule
   138  }
   139  
   140  func getWebsite(r *parser.Resource) *s3.Website {
   141  	if block := r.GetProperty("WebsiteConfiguration"); block.IsNil() {
   142  		return nil
   143  	} else {
   144  		return &s3.Website{
   145  			Metadata: block.Metadata(),
   146  		}
   147  	}
   148  }