github.com/aquasecurity/trivy-iac@v0.8.1-0.20240127024015-3d8e412cf0ab/internal/adapters/terraform/aws/s3/bucket.go (about) 1 package s3 2 3 import ( 4 "github.com/aquasecurity/defsec/pkg/providers/aws/s3" 5 "github.com/aquasecurity/defsec/pkg/terraform" 6 defsecTypes "github.com/aquasecurity/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 sseConfgihuration := block.GetBlock("server_side_encryption_configuration"); sseConfgihuration != nil { 47 return newS3Encryption(block, sseConfgihuration) 48 } 49 if val, ok := applyForBucketRelatedResource(a, block, "aws_s3_bucket_server_side_encryption_configuration", func(resource *terraform.Block) s3.Encryption { 50 return newS3Encryption(resource, resource) 51 }); ok { 52 return val 53 } 54 return s3.Encryption{ 55 Metadata: block.GetMetadata(), 56 Enabled: defsecTypes.BoolDefault(false, block.GetMetadata()), 57 KMSKeyId: defsecTypes.StringDefault("", block.GetMetadata()), 58 Algorithm: defsecTypes.StringDefault("", block.GetMetadata()), 59 } 60 } 61 62 func newS3Encryption(root *terraform.Block, sseConfgihuration *terraform.Block) s3.Encryption { 63 return s3.Encryption{ 64 Metadata: root.GetMetadata(), 65 Enabled: isEncrypted(sseConfgihuration), 66 Algorithm: terraform.MapNestedAttribute( 67 sseConfgihuration, 68 "rule.apply_server_side_encryption_by_default.sse_algorithm", 69 func(attr *terraform.Attribute, parent *terraform.Block) defsecTypes.StringValue { 70 return attr.AsStringValueOrDefault("", parent) 71 }, 72 ), 73 KMSKeyId: terraform.MapNestedAttribute( 74 sseConfgihuration, 75 "rule.apply_server_side_encryption_by_default.kms_master_key_id", 76 func(attr *terraform.Attribute, parent *terraform.Block) defsecTypes.StringValue { 77 return attr.AsStringValueOrDefault("", parent) 78 }, 79 ), 80 } 81 } 82 83 func getVersioning(block *terraform.Block, a *adapter) s3.Versioning { 84 versioning := s3.Versioning{ 85 Metadata: block.GetMetadata(), 86 Enabled: defsecTypes.BoolDefault(false, block.GetMetadata()), 87 MFADelete: defsecTypes.BoolDefault(false, block.GetMetadata()), 88 } 89 if lockBlock := block.GetBlock("object_lock_configuration"); lockBlock != nil { 90 if enabled := isObjeckLockEnabled(lockBlock); enabled != nil { 91 versioning.Enabled = *enabled 92 } 93 } 94 if vBlock := block.GetBlock("versioning"); vBlock != nil { 95 versioning.Enabled = vBlock.GetAttribute("enabled").AsBoolValueOrDefault(true, vBlock) 96 versioning.MFADelete = vBlock.GetAttribute("mfa_delete").AsBoolValueOrDefault(false, vBlock) 97 } 98 99 if enabled, ok := applyForBucketRelatedResource(a, block, "aws_s3_bucket_object_lock_configuration", func(resource *terraform.Block) *defsecTypes.BoolValue { 100 if block.GetAttribute("object_lock_enabled").IsTrue() { 101 return isObjeckLockEnabled(resource) 102 } 103 return nil 104 }); ok && enabled != nil { 105 versioning.Enabled = *enabled 106 } 107 108 if val, ok := applyForBucketRelatedResource(a, block, "aws_s3_bucket_versioning", getVersioningFromResource); ok { 109 return val 110 } 111 return versioning 112 } 113 114 func isObjeckLockEnabled(resource *terraform.Block) *defsecTypes.BoolValue { 115 var val defsecTypes.BoolValue 116 attr := resource.GetAttribute("object_lock_enabled") 117 switch { 118 case attr.IsNil(): // enabled by default 119 val = defsecTypes.BoolDefault(true, resource.GetMetadata()) 120 case attr.Equals("Enabled"): 121 val = defsecTypes.Bool(true, attr.GetMetadata()) 122 } 123 return &val 124 } 125 126 // from aws_s3_bucket_versioning 127 func getVersioningFromResource(block *terraform.Block) s3.Versioning { 128 versioning := s3.Versioning{ 129 Metadata: block.GetMetadata(), 130 Enabled: defsecTypes.BoolDefault(false, block.GetMetadata()), 131 MFADelete: defsecTypes.BoolDefault(false, block.GetMetadata()), 132 } 133 if config := block.GetBlock("versioning_configuration"); config != nil { 134 if status := config.GetAttribute("status"); status.IsNotNil() { 135 versioning.Enabled = defsecTypes.Bool(status.Equals("Enabled", terraform.IgnoreCase), status.GetMetadata()) 136 } 137 if mfa := config.GetAttribute("mfa_delete"); mfa.IsNotNil() { 138 versioning.MFADelete = defsecTypes.Bool(mfa.Equals("Enabled", terraform.IgnoreCase), mfa.GetMetadata()) 139 } 140 } 141 return versioning 142 } 143 144 func getLogging(block *terraform.Block, a *adapter) s3.Logging { 145 if loggingBlock := block.GetBlock("logging"); loggingBlock.IsNotNil() { 146 targetBucket := loggingBlock.GetAttribute("target_bucket").AsStringValueOrDefault("", loggingBlock) 147 if referencedBlock, err := a.modules.GetReferencedBlock(loggingBlock.GetAttribute("target_bucket"), loggingBlock); err == nil { 148 targetBucket = defsecTypes.String(referencedBlock.FullName(), loggingBlock.GetAttribute("target_bucket").GetMetadata()) 149 } 150 return s3.Logging{ 151 Metadata: loggingBlock.GetMetadata(), 152 Enabled: defsecTypes.Bool(true, loggingBlock.GetMetadata()), 153 TargetBucket: targetBucket, 154 } 155 } 156 157 if val, ok := applyForBucketRelatedResource(a, block, "aws_s3_bucket_logging", func(resource *terraform.Block) s3.Logging { 158 targetBucket := resource.GetAttribute("target-bucket").AsStringValueOrDefault("", resource) 159 if referencedBlock, err := a.modules.GetReferencedBlock(resource.GetAttribute("target_bucket"), resource); err == nil { 160 targetBucket = defsecTypes.String(referencedBlock.FullName(), resource.GetAttribute("target_bucket").GetMetadata()) 161 } 162 return s3.Logging{ 163 Metadata: resource.GetMetadata(), 164 Enabled: hasLogging(resource), 165 TargetBucket: targetBucket, 166 } 167 }); ok { 168 return val 169 } 170 171 return s3.Logging{ 172 Metadata: block.GetMetadata(), 173 Enabled: defsecTypes.Bool(false, block.GetMetadata()), 174 TargetBucket: defsecTypes.StringDefault("", block.GetMetadata()), 175 } 176 } 177 178 func getBucketAcl(block *terraform.Block, a *adapter) defsecTypes.StringValue { 179 aclAttr := block.GetAttribute("acl") 180 if aclAttr.IsString() { 181 return aclAttr.AsStringValueOrDefault("private", block) 182 } 183 184 if val, ok := applyForBucketRelatedResource(a, block, "aws_s3_bucket_acl", func(resource *terraform.Block) defsecTypes.StringValue { 185 return resource.GetAttribute("acl").AsStringValueOrDefault("private", resource) 186 }); ok { 187 return val 188 } 189 return defsecTypes.StringDefault("private", block.GetMetadata()) 190 } 191 192 func isEncrypted(sseConfgihuration *terraform.Block) defsecTypes.BoolValue { 193 return terraform.MapNestedAttribute( 194 sseConfgihuration, 195 "rule.apply_server_side_encryption_by_default.sse_algorithm", 196 func(attr *terraform.Attribute, parent *terraform.Block) defsecTypes.BoolValue { 197 if attr.IsNil() { 198 return defsecTypes.BoolDefault(false, parent.GetMetadata()) 199 } 200 return defsecTypes.Bool( 201 true, 202 attr.GetMetadata(), 203 ) 204 }, 205 ) 206 } 207 208 func hasLogging(b *terraform.Block) defsecTypes.BoolValue { 209 if loggingBlock := b.GetBlock("logging"); loggingBlock.IsNotNil() { 210 if targetAttr := loggingBlock.GetAttribute("target_bucket"); targetAttr.IsNotNil() && targetAttr.IsNotEmpty() { 211 return defsecTypes.Bool(true, targetAttr.GetMetadata()) 212 } 213 return defsecTypes.BoolDefault(false, loggingBlock.GetMetadata()) 214 } 215 if targetBucket := b.GetAttribute("target_bucket"); targetBucket.IsNotNil() { 216 return defsecTypes.Bool(true, targetBucket.GetMetadata()) 217 } 218 return defsecTypes.BoolDefault(false, b.GetMetadata()) 219 } 220 221 func getLifecycle(b *terraform.Block, a *adapter) []s3.Rules { 222 223 var rules []s3.Rules 224 for _, r := range a.modules.GetReferencingResources(b, "aws_s3_bucket_lifecycle_configuration", "bucket") { 225 ruleblock := r.GetBlocks("rule") 226 for _, rule := range ruleblock { 227 rules = append(rules, s3.Rules{ 228 Metadata: rule.GetMetadata(), 229 Status: rule.GetAttribute("status").AsStringValueOrDefault("Enabled", rule), 230 }) 231 } 232 } 233 return rules 234 } 235 236 func getWebsite(b *terraform.Block, a *adapter) (website *s3.Website) { 237 for _, r := range a.modules.GetReferencingResources(b, "aws_s3_bucket_website_configuration", "bucket") { 238 website = &s3.Website{ 239 Metadata: r.GetMetadata(), 240 } 241 } 242 return website 243 } 244 245 func getObject(b *terraform.Block, a *adapter) []s3.Contents { 246 var object []s3.Contents 247 for _, r := range a.modules.GetReferencingResources(b, "aws_s3_object", "bucket") { 248 object = append(object, s3.Contents{ 249 Metadata: r.GetMetadata(), 250 }) 251 } 252 return object 253 } 254 255 func getAccelerateStatus(b *terraform.Block, a *adapter) defsecTypes.StringValue { 256 var status defsecTypes.StringValue 257 for _, r := range a.modules.GetReferencingResources(b, " aws_s3_bucket_accelerate_configuration", "bucket") { 258 status = r.GetAttribute("status").AsStringValueOrDefault("Enabled", r) 259 } 260 return status 261 } 262 263 func applyForBucketRelatedResource[T any](a *adapter, block *terraform.Block, resType string, fn func(resource *terraform.Block) T) (T, bool) { 264 for _, resource := range a.modules.GetResourcesByType(resType) { 265 bucketAttr := resource.GetAttribute("bucket") 266 if bucketAttr.IsNotNil() { 267 if bucketAttr.IsString() { 268 actualBucketName := block.GetAttribute("bucket").AsStringValueOrDefault("", block).Value() 269 if bucketAttr.Equals(block.ID()) || bucketAttr.Equals(actualBucketName) { 270 return fn(resource), true 271 } 272 } 273 if referencedBlock, err := a.modules.GetReferencedBlock(bucketAttr, resource); err == nil { 274 if referencedBlock.ID() == block.ID() { 275 return fn(resource), true 276 } 277 } 278 } 279 280 } 281 var res T 282 return res, false 283 }