Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(s3): S3_002: check bucket has no replication to other region #87

Merged
merged 4 commits into from
Mar 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ The available log levels are: `debug`, `info`, `warn`, `error`, `fatal`, `panic`

### S3 Bucket
- AWS_S3_001 S3 are encrypted
- AWS_S3_002 S3 buckets are not global but in one zone
- AWS_S3_002 S3 buckets are not replicated to another region
- AWS_S3_003 S3 buckets are versioned
- AWS_S3_004 S3 buckets have a retention policy
- AWS_S3_005 S3 bucket have public access block enabled
Expand Down
55 changes: 54 additions & 1 deletion aws/s3/getter.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ package s3

import (
"context"
"errors"
"fmt"
"strings"

"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/s3"
"github.com/aws/aws-sdk-go-v2/service/s3/types"
"github.com/aws/smithy-go"
)

func GetListS3(s aws.Config) []types.Bucket {
Expand Down Expand Up @@ -39,7 +41,8 @@ func GetListS3NotInRegion(s aws.Config, region string) []types.Bucket {

var buckets []types.Bucket
for _, bucket := range resp.Buckets {
if !CheckS3Location(s, *bucket.Name, region) {
check, _ := CheckS3Location(s, *bucket.Name, region)
if !check {
buckets = append(buckets, bucket)
}
}
Expand Down Expand Up @@ -157,3 +160,53 @@ func GetS3ToObjectLock(s aws.Config, b []types.Bucket) []S3ToObjectLock {

return s3toObjectLock
}

type S3ToReplicationOtherRegion struct {
BucketName string
ReplicatedOtherRegion bool
OtherRegion string
}

func GetS3ToReplicationOtherRegion(s aws.Config, b []types.Bucket) []S3ToReplicationOtherRegion {

svc := s3.NewFromConfig(s)

var s3toReplicationOtherRegion []S3ToReplicationOtherRegion
for _, bucket := range b {
params := &s3.GetBucketReplicationInput{
Bucket: aws.String(*bucket.Name),
}
resp, err := svc.GetBucketReplication(context.TODO(), params)
if err != nil {
var ae smithy.APIError
if errors.As(err, &ae) && ae.ErrorCode() == "ReplicationConfigurationNotFoundError" {
s3toReplicationOtherRegion = append(s3toReplicationOtherRegion, S3ToReplicationOtherRegion{*bucket.Name, false, ""})
continue
}
fmt.Println(err)
// return empty struct
return []S3ToReplicationOtherRegion{}
}
if resp.ReplicationConfiguration == nil {
s3toReplicationOtherRegion = append(s3toReplicationOtherRegion, S3ToReplicationOtherRegion{*bucket.Name, false, ""})
} else {
// Check the region of destination buckets
found := false
for _, rule := range resp.ReplicationConfiguration.Rules {
replicationTarget := strings.TrimPrefix(*rule.Destination.Bucket, "arn:aws:s3:::")
if ok, otherRegion := CheckS3Location(s, replicationTarget, s.Region); !ok {
s3toReplicationOtherRegion = append(s3toReplicationOtherRegion, S3ToReplicationOtherRegion{*bucket.Name, true, otherRegion})
found = true
break // break the loop if at least one of the replication rule is to other region
}
}

// no destination rule to other region
if !found {
s3toReplicationOtherRegion = append(s3toReplicationOtherRegion, S3ToReplicationOtherRegion{*bucket.Name, false, ""})
}
}
}

return s3toReplicationOtherRegion
}
22 changes: 12 additions & 10 deletions aws/s3/s3.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ import (
"github.com/padok-team/yatas/plugins/commons"
)

func CheckS3Location(s aws.Config, bucket, region string) bool {
// Return true if the bucket is in the region, false with the correct region if not
func CheckS3Location(s aws.Config, bucket, region string) (bool, string) {

svc := s3.NewFromConfig(s)

Expand All @@ -19,19 +20,19 @@ func CheckS3Location(s aws.Config, bucket, region string) bool {
}
resp, err := svc.GetBucketLocation(context.TODO(), params)
if err != nil {

return false
return false, ""
}

if resp.LocationConstraint != "" {
if string(resp.LocationConstraint) == region {
return true
if string(resp.LocationConstraint) == region {
return true, region
} else if string(resp.LocationConstraint) == "" { // If the bucket is in us-east-1, the LocationConstraint is empty
if region == "us-east-1" {
return true, region
} else {
return false
return false, "us-east-1"
}

} else {
return false
return false, string(resp.LocationConstraint)
}
}

Expand All @@ -53,9 +54,10 @@ func RunChecks(wa *sync.WaitGroup, s aws.Config, c *commons.Config, queue chan [
S3toPublicBlockAccess := GetS3ToPublicBlockAccess(s, OnlyBucketInRegion)
S3ToVersioning := GetS3ToVersioning(s, OnlyBucketInRegion)
S3ToObjectLock := GetS3ToObjectLock(s, OnlyBucketInRegion)
S3ToReplicationOtherRegion := GetS3ToReplicationOtherRegion(s, OnlyBucketInRegion)

go commons.CheckTest(checkConfig.Wg, c, "AWS_S3_001", checkIfEncryptionEnabled)(checkConfig, S3ToEncryption, "AWS_S3_001")
go commons.CheckTest(checkConfig.Wg, c, "AWS_S3_002", CheckIfBucketInOneZone)(checkConfig, couple, "AWS_S3_002")
go commons.CheckTest(checkConfig.Wg, c, "AWS_S3_002", CheckIfBucketNoReplicationOtherRegion)(checkConfig, S3ToReplicationOtherRegion, "AWS_S3_002")
go commons.CheckTest(checkConfig.Wg, c, "AWS_S3_003", CheckIfBucketObjectVersioningEnabled)(checkConfig, S3ToVersioning, "AWS_S3_003")
go commons.CheckTest(checkConfig.Wg, c, "AWS_S3_004", CheckIfObjectLockConfigurationEnabled)(checkConfig, S3ToObjectLock, "AWS_S3_004")
go commons.CheckTest(checkConfig.Wg, c, "AWS_S3_005", CheckIfS3PublicAccessBlockEnabled)(checkConfig, S3toPublicBlockAccess, "AWS_S3_005")
Expand Down
22 changes: 22 additions & 0 deletions aws/s3/s3NoReplication.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package s3

import (
"github.com/padok-team/yatas/plugins/commons"
)

func CheckIfBucketNoReplicationOtherRegion(checkConfig commons.CheckConfig, buckets []S3ToReplicationOtherRegion, testName string) {
var check commons.Check
check.InitCheck("S3 buckets are not replicated to another region", "Check if S3 buckets are replicated to other region", testName, []string{"Security", "Good Practice"})
for _, bucket := range buckets {
if bucket.ReplicatedOtherRegion {
Message := "S3 bucket " + bucket.BucketName + " is replicated to the " + bucket.OtherRegion + " region"
result := commons.Result{Status: "FAIL", Message: Message, ResourceID: bucket.BucketName}
check.AddResult(result)
} else {
Message := "S3 bucket " + bucket.BucketName + " is not replicated to another region"
result := commons.Result{Status: "OK", Message: Message, ResourceID: bucket.BucketName}
check.AddResult(result)
}
}
checkConfig.Queue <- check
}
58 changes: 22 additions & 36 deletions aws/s3/s3OneRegion_test.go → aws/s3/s3NoReplication_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,52 +4,44 @@ import (
"sync"
"testing"

"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/s3/types"
"github.com/padok-team/yatas/plugins/commons"
)

func TestCheckIfBucketInOneZone(t *testing.T) {
func Test_checkIfReplicationDisabled(t *testing.T) {
type args struct {
checkConfig commons.CheckConfig
buckets BucketAndNotInRegion
buckets []S3ToReplicationOtherRegion
testName string
}
tests := []struct {
name string
args args
}{
{
name: "Check if S3 buckets are in one zone",
name: "check if replication disabled",
args: args{
checkConfig: commons.CheckConfig{
Wg: &sync.WaitGroup{},
Queue: make(chan commons.Check, 1),
Wg: &sync.WaitGroup{},
},
buckets: BucketAndNotInRegion{
Buckets: []types.Bucket{
{
Name: aws.String("test"),
},
},
NotInRegion: []types.Bucket{
{
Name: aws.String("toto"),
},
buckets: []S3ToReplicationOtherRegion{
{
BucketName: "test",
ReplicatedOtherRegion: false,
OtherRegion: "",
},
},
testName: "AWS_S3_001",
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
CheckIfBucketInOneZone(tt.args.checkConfig, tt.args.buckets, tt.args.testName)
CheckIfBucketNoReplicationOtherRegion(tt.args.checkConfig, tt.args.buckets, tt.args.testName)
tt.args.checkConfig.Wg.Add(1)
go func() {
for check := range tt.args.checkConfig.Queue {
if check.Status != "OK" {
t.Errorf("CheckIfBucketInOneZone() = %v", check)
t.Errorf("CheckIfBucketNoReplicationOtherRegion() = %v", check)
}
tt.args.checkConfig.Wg.Done()
}
Expand All @@ -59,47 +51,41 @@ func TestCheckIfBucketInOneZone(t *testing.T) {
}
}

func TestCheckIfBucketInOneZoneFail(t *testing.T) {
func Test_checkIfReplicationDisabledFail(t *testing.T) {
type args struct {
checkConfig commons.CheckConfig
buckets BucketAndNotInRegion
buckets []S3ToReplicationOtherRegion
testName string
}
tests := []struct {
name string
args args
}{
{
name: "Check if S3 buckets are in one zone",
name: "check if replication disabled",
args: args{
checkConfig: commons.CheckConfig{
Wg: &sync.WaitGroup{},
Queue: make(chan commons.Check, 1),
Wg: &sync.WaitGroup{},
},
buckets: BucketAndNotInRegion{
Buckets: []types.Bucket{
{
Name: aws.String("test"),
},
},
NotInRegion: []types.Bucket{
{
Name: aws.String("test"),
},
buckets: []S3ToReplicationOtherRegion{
{
BucketName: "test",
ReplicatedOtherRegion: true,
OtherRegion: "eu-west-1",
},
},
testName: "AWS_S3_001",
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
CheckIfBucketInOneZone(tt.args.checkConfig, tt.args.buckets, tt.args.testName)
CheckIfBucketNoReplicationOtherRegion(tt.args.checkConfig, tt.args.buckets, tt.args.testName)
tt.args.checkConfig.Wg.Add(1)
go func() {
for check := range tt.args.checkConfig.Queue {
if check.Status != "FAIL" {
t.Errorf("CheckIfBucketInOneZone() = %v", check)
t.Errorf("CheckIfBucketNoReplicationOtherRegion() = %v", check)
}
tt.args.checkConfig.Wg.Done()
}
Expand Down
28 changes: 0 additions & 28 deletions aws/s3/s3OneRegion.go

This file was deleted.

2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ require (
github.com/aws/aws-sdk-go-v2/service/lambda v1.29.4
github.com/aws/aws-sdk-go-v2/service/rds v1.40.7
github.com/aws/aws-sdk-go-v2/service/s3 v1.30.6
github.com/aws/smithy-go v1.13.5
github.com/hashicorp/go-hclog v1.4.0
github.com/hashicorp/go-plugin v1.4.9
github.com/mitchellh/mapstructure v1.5.0
Expand All @@ -45,7 +46,6 @@ require (
github.com/aws/aws-sdk-go-v2/service/sso v1.12.6 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.6 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.18.7 // indirect
github.com/aws/smithy-go v1.13.5 // indirect
github.com/fatih/color v1.14.1 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/google/go-github/v35 v35.3.0 // indirect
Expand Down