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

     1  package s3
     2  
     3  import (
     4  	"testing"
     5  
     6  	defsecTypes "github.com/khulnasoft-lab/defsec/pkg/types"
     7  
     8  	"github.com/khulnasoft-lab/defsec/internal/adapters/terraform/tftestutil"
     9  	"github.com/khulnasoft-lab/defsec/pkg/providers/aws/iam"
    10  	"github.com/khulnasoft-lab/defsec/pkg/providers/aws/s3"
    11  	"github.com/khulnasoft-lab/defsec/test/testutil"
    12  	"github.com/liamg/iamgo"
    13  	"github.com/stretchr/testify/assert"
    14  	"github.com/stretchr/testify/require"
    15  )
    16  
    17  func Test_PublicAccessBlock(t *testing.T) {
    18  	testCases := []struct {
    19  		desc            string
    20  		source          string
    21  		expectedBuckets int
    22  		hasPublicAccess bool
    23  	}{
    24  		{
    25  			desc: "public access block is found when using the bucket name as the lookup",
    26  			source: `
    27  resource "aws_s3_bucket" "example" {
    28  	bucket = "bucketname"
    29  }
    30  
    31  resource "aws_s3_bucket_public_access_block" "example_access_block"{
    32  	bucket = "bucketname"
    33  }
    34  `,
    35  			expectedBuckets: 1,
    36  			hasPublicAccess: true,
    37  		},
    38  		{
    39  			desc: "public access block is found when using the bucket name as the lookup",
    40  			source: `
    41  resource "aws_s3_bucket" "example" {
    42  	bucket = "bucketname"
    43  }
    44  
    45  resource "aws_s3_bucket_public_access_block" "example_access_block"{
    46  	bucket = aws_s3_bucket.example.id
    47  }
    48  `,
    49  			expectedBuckets: 1,
    50  			hasPublicAccess: true,
    51  		},
    52  	}
    53  	for _, tC := range testCases {
    54  		t.Run(tC.desc, func(t *testing.T) {
    55  
    56  			modules := tftestutil.CreateModulesFromSource(t, tC.source, ".tf")
    57  			s3Ctx := Adapt(modules)
    58  
    59  			assert.Equal(t, tC.expectedBuckets, len(s3Ctx.Buckets))
    60  
    61  			for _, bucket := range s3Ctx.Buckets {
    62  				if tC.hasPublicAccess {
    63  					assert.NotNil(t, bucket.PublicAccessBlock)
    64  				} else {
    65  					assert.Nil(t, bucket.PublicAccessBlock)
    66  				}
    67  			}
    68  
    69  			bucket := s3Ctx.Buckets[0]
    70  			assert.NotNil(t, bucket.PublicAccessBlock)
    71  
    72  		})
    73  	}
    74  
    75  }
    76  
    77  func Test_PublicAccessDoesNotReference(t *testing.T) {
    78  	testCases := []struct {
    79  		desc   string
    80  		source string
    81  	}{
    82  		{
    83  			desc: "just a bucket, no public access block",
    84  			source: `
    85  resource "aws_s3_bucket" "example" {
    86  	bucket = "bucketname"
    87  }
    88  			`,
    89  		},
    90  		{
    91  			desc: "bucket with unrelated public access block",
    92  			source: `
    93  resource "aws_s3_bucket" "example" {
    94  	bucket = "bucketname"
    95  }
    96  
    97  resource "aws_s3_bucket_public_access_block" "example_access_block"{
    98  	bucket = aws_s3_bucket.other.id
    99  }
   100  			`,
   101  		},
   102  		{
   103  			desc: "bucket with unrelated public access block via name",
   104  			source: `
   105  resource "aws_s3_bucket" "example" {
   106  	bucket = "bucketname"
   107  }
   108  
   109  resource "aws_s3_bucket_public_access_block" "example_access_block"{
   110  	bucket = "something"
   111  }
   112  			`,
   113  		},
   114  	}
   115  	for _, tC := range testCases {
   116  		t.Run(tC.desc, func(t *testing.T) {
   117  			modules := tftestutil.CreateModulesFromSource(t, tC.source, ".tf")
   118  			s3Ctx := Adapt(modules)
   119  			require.Len(t, s3Ctx.Buckets, 1)
   120  			assert.Nil(t, s3Ctx.Buckets[0].PublicAccessBlock)
   121  
   122  		})
   123  	}
   124  }
   125  
   126  func Test_Adapt(t *testing.T) {
   127  	tests := []struct {
   128  		name      string
   129  		terraform string
   130  		expected  s3.S3
   131  	}{
   132  		{
   133  			name: "basic",
   134  			terraform: `
   135  			resource "aws_s3_bucket" "example" {
   136  				bucket = "bucket"
   137  			}
   138  			
   139  			resource "aws_s3_bucket_public_access_block" "example" {
   140  				 bucket = aws_s3_bucket.example.id
   141  			   
   142  				 restrict_public_buckets = true
   143  				 block_public_acls   = true
   144  				 block_public_policy = true
   145  				 ignore_public_acls = true
   146  
   147  			 }
   148  
   149  			 resource "aws_s3_bucket_acl" "example" {
   150  				bucket = aws_s3_bucket.example.id
   151  				acl    = "private"
   152  			  }
   153  
   154  			  resource "aws_s3_bucket_server_side_encryption_configuration" "example" {
   155  				bucket = aws_s3_bucket.example.bucket
   156  			  
   157  				rule {
   158  				  apply_server_side_encryption_by_default {
   159  					kms_master_key_id = "string-key"
   160  					sse_algorithm     = "aws:kms"
   161  				  }
   162  				}
   163  			  }
   164  
   165  			  resource "aws_s3_bucket_logging" "example" {
   166  				bucket = aws_s3_bucket.example.id
   167  			  
   168  				target_bucket = aws_s3_bucket.example.id
   169  				target_prefix = "log/"
   170  			  }
   171  
   172  			  resource "aws_s3_bucket_versioning" "versioning_example" {
   173  				bucket = aws_s3_bucket.example.id
   174  				versioning_configuration {
   175  				  status = "Enabled"
   176                    mfa_delete = "Enabled"
   177  				}
   178  			  }
   179  
   180  			  resource "aws_s3_bucket_policy" "allow_access_from_another_account" {
   181  				bucket = aws_s3_bucket.example.bucket
   182  				policy = data.aws_iam_policy_document.allow_access_from_another_account.json
   183  			  }
   184  			  
   185  			  data "aws_iam_policy_document" "allow_access_from_another_account" {
   186  				statement {
   187  			  
   188  				  actions = [
   189  					"s3:GetObject",
   190  					"s3:ListBucket",
   191  				  ]
   192  			  
   193  				  resources = [
   194  					"arn:aws:s3:::*",
   195  				  ]
   196  				}
   197  			  }
   198  		`,
   199  			expected: s3.S3{
   200  				Buckets: []s3.Bucket{
   201  					{
   202  						Metadata: defsecTypes.NewTestMetadata(),
   203  						Name:     defsecTypes.String("bucket", defsecTypes.NewTestMetadata()),
   204  						PublicAccessBlock: &s3.PublicAccessBlock{
   205  							Metadata:              defsecTypes.NewTestMetadata(),
   206  							BlockPublicACLs:       defsecTypes.Bool(true, defsecTypes.NewTestMetadata()),
   207  							BlockPublicPolicy:     defsecTypes.Bool(true, defsecTypes.NewTestMetadata()),
   208  							IgnorePublicACLs:      defsecTypes.Bool(true, defsecTypes.NewTestMetadata()),
   209  							RestrictPublicBuckets: defsecTypes.Bool(true, defsecTypes.NewTestMetadata()),
   210  						},
   211  						BucketPolicies: []iam.Policy{
   212  							{
   213  								Metadata: defsecTypes.NewTestMetadata(),
   214  								Name:     defsecTypes.String("", defsecTypes.NewTestMetadata()),
   215  								Document: func() iam.Document {
   216  
   217  									builder := iamgo.NewPolicyBuilder()
   218  
   219  									sb := iamgo.NewStatementBuilder()
   220  									sb.WithEffect(iamgo.EffectAllow)
   221  									sb.WithActions([]string{"s3:GetObject", "s3:ListBucket"})
   222  									sb.WithResources([]string{"arn:aws:s3:::*"})
   223  
   224  									builder.WithStatement(sb.Build())
   225  
   226  									return iam.Document{
   227  										Parsed:   builder.Build(),
   228  										Metadata: defsecTypes.NewTestMetadata(),
   229  										IsOffset: true,
   230  										HasRefs:  false,
   231  									}
   232  								}(),
   233  								Builtin: defsecTypes.Bool(false, defsecTypes.NewTestMetadata()),
   234  							},
   235  						},
   236  						Encryption: s3.Encryption{
   237  							Metadata:  defsecTypes.NewTestMetadata(),
   238  							Enabled:   defsecTypes.Bool(true, defsecTypes.NewTestMetadata()),
   239  							Algorithm: defsecTypes.String("aws:kms", defsecTypes.NewTestMetadata()),
   240  							KMSKeyId:  defsecTypes.String("string-key", defsecTypes.NewTestMetadata()),
   241  						},
   242  						Versioning: s3.Versioning{
   243  							Metadata:  defsecTypes.NewTestMetadata(),
   244  							Enabled:   defsecTypes.Bool(true, defsecTypes.NewTestMetadata()),
   245  							MFADelete: defsecTypes.Bool(true, defsecTypes.NewTestMetadata()),
   246  						},
   247  						Logging: s3.Logging{
   248  							Metadata:     defsecTypes.NewTestMetadata(),
   249  							Enabled:      defsecTypes.Bool(true, defsecTypes.NewTestMetadata()),
   250  							TargetBucket: defsecTypes.String("aws_s3_bucket.example", defsecTypes.NewTestMetadata()),
   251  						},
   252  						ACL: defsecTypes.String("private", defsecTypes.NewTestMetadata()),
   253  					},
   254  				},
   255  			},
   256  		},
   257  	}
   258  
   259  	for _, test := range tests {
   260  		t.Run(test.name, func(t *testing.T) {
   261  			modules := tftestutil.CreateModulesFromSource(t, test.terraform, ".tf")
   262  			adapted := Adapt(modules)
   263  			testutil.AssertDefsecEqual(t, test.expected, adapted)
   264  		})
   265  	}
   266  }
   267  
   268  func TestLines(t *testing.T) {
   269  	src := `
   270  		resource "aws_s3_bucket" "example" {
   271  			bucket = "bucket"
   272  		}
   273  
   274  		resource "aws_s3_bucket_public_access_block" "example" {
   275  			bucket = aws_s3_bucket.example.id
   276  		
   277  			restrict_public_buckets = true
   278  			block_public_acls   = true
   279  			block_public_policy = true
   280  			ignore_public_acls = true
   281  		}
   282  
   283  		resource "aws_s3_bucket_acl" "example" {
   284  			bucket = aws_s3_bucket.example.id
   285  			acl    = "private"
   286  		}
   287  
   288  		resource "aws_s3_bucket_server_side_encryption_configuration" "example" {
   289  			bucket = aws_s3_bucket.example.bucket
   290  		
   291  			rule {
   292  			apply_server_side_encryption_by_default {
   293  				kms_master_key_id = "string-key"
   294  				sse_algorithm     = "aws:kms"
   295  			}
   296  			}
   297  		}
   298  
   299  		resource "aws_s3_bucket_logging" "example" {
   300  			bucket = aws_s3_bucket.example.id
   301  		
   302  			target_bucket = aws_s3_bucket.example.id
   303  			target_prefix = "log/"
   304  		}
   305  
   306  		resource "aws_s3_bucket_versioning" "versioning_example" {
   307  			bucket = aws_s3_bucket.example.id
   308  			versioning_configuration {
   309  			status = "Enabled"
   310  			}
   311  		}
   312  
   313  		resource "aws_s3_bucket_policy" "allow_access_from_another_account" {
   314  			bucket = aws_s3_bucket.example.bucket
   315  			policy = data.aws_iam_policy_document.allow_access_from_another_account.json
   316  		}
   317  		
   318  		data "aws_iam_policy_document" "allow_access_from_another_account" {
   319  			statement {
   320  		
   321  			actions = [
   322  				"s3:GetObject",
   323  				"s3:ListBucket",
   324  			]
   325  		
   326  			resources = [
   327  				"arn:aws:s3:::*",
   328  			]
   329  			}
   330  		}`
   331  
   332  	modules := tftestutil.CreateModulesFromSource(t, src, ".tf")
   333  	adapted := Adapt(modules)
   334  
   335  	require.Len(t, adapted.Buckets, 1)
   336  	bucket := adapted.Buckets[0]
   337  
   338  	assert.Equal(t, 2, bucket.Metadata.Range().GetStartLine())
   339  	assert.Equal(t, 4, bucket.Metadata.Range().GetEndLine())
   340  
   341  	assert.Equal(t, 6, bucket.PublicAccessBlock.Metadata.Range().GetStartLine())
   342  	assert.Equal(t, 13, bucket.PublicAccessBlock.Metadata.Range().GetEndLine())
   343  
   344  	assert.Equal(t, 9, bucket.PublicAccessBlock.RestrictPublicBuckets.GetMetadata().Range().GetStartLine())
   345  	assert.Equal(t, 9, bucket.PublicAccessBlock.RestrictPublicBuckets.GetMetadata().Range().GetEndLine())
   346  
   347  	assert.Equal(t, 10, bucket.PublicAccessBlock.BlockPublicACLs.GetMetadata().Range().GetStartLine())
   348  	assert.Equal(t, 10, bucket.PublicAccessBlock.BlockPublicACLs.GetMetadata().Range().GetEndLine())
   349  
   350  	assert.Equal(t, 11, bucket.PublicAccessBlock.BlockPublicPolicy.GetMetadata().Range().GetStartLine())
   351  	assert.Equal(t, 11, bucket.PublicAccessBlock.BlockPublicPolicy.GetMetadata().Range().GetEndLine())
   352  
   353  	assert.Equal(t, 12, bucket.PublicAccessBlock.IgnorePublicACLs.GetMetadata().Range().GetStartLine())
   354  	assert.Equal(t, 12, bucket.PublicAccessBlock.IgnorePublicACLs.GetMetadata().Range().GetEndLine())
   355  
   356  	assert.Equal(t, 17, bucket.ACL.GetMetadata().Range().GetStartLine())
   357  	assert.Equal(t, 17, bucket.ACL.GetMetadata().Range().GetEndLine())
   358  
   359  	assert.Equal(t, 20, bucket.Encryption.Metadata.Range().GetStartLine())
   360  	assert.Equal(t, 29, bucket.Encryption.Metadata.Range().GetEndLine())
   361  
   362  	assert.Equal(t, 25, bucket.Encryption.KMSKeyId.GetMetadata().Range().GetStartLine())
   363  	assert.Equal(t, 25, bucket.Encryption.KMSKeyId.GetMetadata().Range().GetEndLine())
   364  
   365  	assert.Equal(t, 26, bucket.Encryption.Algorithm.GetMetadata().Range().GetStartLine())
   366  	assert.Equal(t, 26, bucket.Encryption.Algorithm.GetMetadata().Range().GetEndLine())
   367  
   368  	assert.Equal(t, 31, bucket.Logging.Metadata.Range().GetStartLine())
   369  	assert.Equal(t, 36, bucket.Logging.Metadata.Range().GetEndLine())
   370  
   371  	assert.Equal(t, 34, bucket.Logging.TargetBucket.GetMetadata().Range().GetStartLine())
   372  	assert.Equal(t, 34, bucket.Logging.TargetBucket.GetMetadata().Range().GetEndLine())
   373  
   374  	assert.Equal(t, 38, bucket.Versioning.Metadata.Range().GetStartLine())
   375  	assert.Equal(t, 43, bucket.Versioning.Metadata.Range().GetEndLine())
   376  
   377  	assert.Equal(t, 41, bucket.Versioning.Enabled.GetMetadata().Range().GetStartLine())
   378  	assert.Equal(t, 41, bucket.Versioning.Enabled.GetMetadata().Range().GetEndLine())
   379  
   380  	assert.Equal(t, 47, bucket.BucketPolicies[0].Metadata.Range().GetStartLine())
   381  	assert.Equal(t, 47, bucket.BucketPolicies[0].Metadata.Range().GetEndLine())
   382  
   383  	assert.Equal(t, 50, bucket.BucketPolicies[0].Document.Metadata.Range().GetStartLine())
   384  	assert.Equal(t, 62, bucket.BucketPolicies[0].Document.Metadata.Range().GetEndLine())
   385  }