feat: add suport for aws_cloudtrail resources
parent
a28bac977c
commit
c65846a263
|
@ -0,0 +1,46 @@
|
|||
package aws
|
||||
|
||||
import (
|
||||
"github.com/snyk/driftctl/enumeration/remote/aws/repository"
|
||||
remoteerror "github.com/snyk/driftctl/enumeration/remote/error"
|
||||
"github.com/snyk/driftctl/enumeration/resource"
|
||||
"github.com/snyk/driftctl/enumeration/resource/aws"
|
||||
)
|
||||
|
||||
type CloudtrailEnumerator struct {
|
||||
repository repository.CloudtrailRepository
|
||||
factory resource.ResourceFactory
|
||||
}
|
||||
|
||||
func NewCloudtrailEnumerator(repo repository.CloudtrailRepository, factory resource.ResourceFactory) *CloudtrailEnumerator {
|
||||
return &CloudtrailEnumerator{
|
||||
repository: repo,
|
||||
factory: factory,
|
||||
}
|
||||
}
|
||||
|
||||
func (e *CloudtrailEnumerator) SupportedType() resource.ResourceType {
|
||||
return aws.AwsCloudtrailResourceType
|
||||
}
|
||||
|
||||
func (e *CloudtrailEnumerator) Enumerate() ([]*resource.Resource, error) {
|
||||
trails, err := e.repository.ListAllTrails()
|
||||
if err != nil {
|
||||
return nil, remoteerror.NewResourceListingError(err, string(e.SupportedType()))
|
||||
}
|
||||
|
||||
results := make([]*resource.Resource, 0, len(trails))
|
||||
|
||||
for _, trail := range trails {
|
||||
results = append(
|
||||
results,
|
||||
e.factory.CreateAbstractResource(
|
||||
string(e.SupportedType()),
|
||||
*trail.Name,
|
||||
map[string]interface{}{},
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
return results, err
|
||||
}
|
|
@ -49,6 +49,7 @@ func Init(version string, alerter alerter.AlerterInterface, providerLibrary *ter
|
|||
kmsRepository := repository.NewKMSRepository(provider.session, repositoryCache)
|
||||
iamRepository := repository.NewIAMRepository(provider.session, repositoryCache)
|
||||
cloudformationRepository := repository.NewCloudformationRepository(provider.session, repositoryCache)
|
||||
cloudtrailRepository := repository.NewCloudtrailRepository(provider.session, repositoryCache)
|
||||
apigatewayRepository := repository.NewApiGatewayRepository(provider.session, repositoryCache)
|
||||
appAutoScalingRepository := repository.NewAppAutoScalingRepository(provider.session, repositoryCache)
|
||||
apigatewayv2Repository := repository.NewApiGatewayV2Repository(provider.session, repositoryCache)
|
||||
|
@ -195,6 +196,9 @@ func Init(version string, alerter alerter.AlerterInterface, providerLibrary *ter
|
|||
remoteLibrary.AddEnumerator(NewCloudformationStackEnumerator(cloudformationRepository, factory))
|
||||
remoteLibrary.AddDetailsFetcher(aws.AwsCloudformationStackResourceType, common.NewGenericDetailsFetcher(aws.AwsCloudformationStackResourceType, provider, deserializer))
|
||||
|
||||
remoteLibrary.AddEnumerator(NewCloudtrailEnumerator(cloudtrailRepository, factory))
|
||||
remoteLibrary.AddDetailsFetcher(aws.AwsCloudtrailResourceType, common.NewGenericDetailsFetcher(aws.AwsCloudtrailResourceType, provider, deserializer))
|
||||
|
||||
remoteLibrary.AddEnumerator(NewApiGatewayRestApiEnumerator(apigatewayRepository, factory))
|
||||
remoteLibrary.AddEnumerator(NewApiGatewayAccountEnumerator(apigatewayRepository, factory))
|
||||
remoteLibrary.AddEnumerator(NewApiGatewayApiKeyEnumerator(apigatewayRepository, factory))
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
package repository
|
||||
|
||||
import (
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/service/cloudtrail"
|
||||
"github.com/aws/aws-sdk-go/service/cloudtrail/cloudtrailiface"
|
||||
"github.com/snyk/driftctl/enumeration/remote/cache"
|
||||
)
|
||||
|
||||
type CloudtrailRepository interface {
|
||||
ListAllTrails() ([]*cloudtrail.TrailInfo, error)
|
||||
}
|
||||
|
||||
type cloudtrailRepository struct {
|
||||
client cloudtrailiface.CloudTrailAPI
|
||||
cache cache.Cache
|
||||
}
|
||||
|
||||
func NewCloudtrailRepository(session *session.Session, c cache.Cache) *cloudtrailRepository {
|
||||
return &cloudtrailRepository{
|
||||
cloudtrail.New(session),
|
||||
c,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *cloudtrailRepository) ListAllTrails() ([]*cloudtrail.TrailInfo, error) {
|
||||
cacheKey := "ListAllTrails"
|
||||
if v := r.cache.Get(cacheKey); v != nil {
|
||||
return v.([]*cloudtrail.TrailInfo), nil
|
||||
}
|
||||
|
||||
var trails []*cloudtrail.TrailInfo
|
||||
input := cloudtrail.ListTrailsInput{}
|
||||
err := r.client.ListTrailsPages(&input,
|
||||
func(resp *cloudtrail.ListTrailsOutput, lastPage bool) bool {
|
||||
if resp.Trails != nil {
|
||||
trails = append(trails, resp.Trails...)
|
||||
}
|
||||
return !lastPage
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
r.cache.Put(cacheKey, trails)
|
||||
return trails, nil
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
package repository
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/snyk/driftctl/enumeration/remote/cache"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/cloudtrail"
|
||||
awstest "github.com/snyk/driftctl/test/aws"
|
||||
|
||||
"github.com/stretchr/testify/mock"
|
||||
|
||||
"github.com/r3labs/diff/v2"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_cloudtrailRepository_ListAllTrails(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
mocks func(client *awstest.MockFakeCloudtrail)
|
||||
want []*cloudtrail.TrailInfo
|
||||
wantErr error
|
||||
}{
|
||||
{
|
||||
name: "list multiple trail",
|
||||
mocks: func(client *awstest.MockFakeCloudtrail) {
|
||||
client.On("ListTrailsPages",
|
||||
&cloudtrail.ListTrailsInput{},
|
||||
mock.MatchedBy(func(callback func(res *cloudtrail.ListTrailsOutput, lastPage bool) bool) bool {
|
||||
callback(&cloudtrail.ListTrailsOutput{
|
||||
Trails: []*cloudtrail.TrailInfo{
|
||||
{Name: aws.String("trail1")},
|
||||
{Name: aws.String("trail2")},
|
||||
{Name: aws.String("trail3")},
|
||||
},
|
||||
}, false)
|
||||
callback(&cloudtrail.ListTrailsOutput{
|
||||
Trails: []*cloudtrail.TrailInfo{
|
||||
{Name: aws.String("trail4")},
|
||||
{Name: aws.String("trail5")},
|
||||
{Name: aws.String("trail6")},
|
||||
},
|
||||
}, true)
|
||||
return true
|
||||
})).Return(nil).Once()
|
||||
},
|
||||
want: []*cloudtrail.TrailInfo{
|
||||
{Name: aws.String("trail1")},
|
||||
{Name: aws.String("trail2")},
|
||||
{Name: aws.String("trail3")},
|
||||
{Name: aws.String("trail4")},
|
||||
{Name: aws.String("trail5")},
|
||||
{Name: aws.String("trail6")},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
store := cache.New(1)
|
||||
client := awstest.MockFakeCloudtrail{}
|
||||
tt.mocks(&client)
|
||||
r := &cloudtrailRepository{
|
||||
client: &client,
|
||||
cache: store,
|
||||
}
|
||||
got, err := r.ListAllTrails()
|
||||
assert.Equal(t, tt.wantErr, err)
|
||||
|
||||
if err == nil {
|
||||
// Check that results were cached
|
||||
cachedData, err := r.ListAllTrails()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, got, cachedData)
|
||||
assert.IsType(t, []*cloudtrail.TrailInfo{}, store.Get("ListAllTrails"))
|
||||
}
|
||||
|
||||
changelog, err := diff.Diff(got, tt.want)
|
||||
assert.Nil(t, err)
|
||||
if len(changelog) > 0 {
|
||||
for _, change := range changelog {
|
||||
t.Errorf("%s: %s -> %s", strings.Join(change.Path, "."), change.From, change.To)
|
||||
}
|
||||
t.Fail()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
package aws
|
||||
|
||||
const AwsCloudtrailResourceType = "aws_cloudtrail"
|
|
@ -175,6 +175,7 @@ var supportedTypes = map[string]ResourceTypeMeta{
|
|||
"aws_launch_configuration": {},
|
||||
"aws_elb": {},
|
||||
"aws_elasticache_cluster": {},
|
||||
"aws_cloudtrail": {},
|
||||
|
||||
"github_branch_protection": {},
|
||||
"github_membership": {},
|
||||
|
|
|
@ -210,6 +210,7 @@ func TestTerraformStateReader_AWS_Resources(t *testing.T) {
|
|||
{name: "ElastiCache Cluster", dirName: "aws_elasticache_cluster", wantErr: false},
|
||||
{name: "IAM Group", dirName: "aws_iam_group", wantErr: false},
|
||||
{name: "ECR Repository Policy", dirName: "aws_ecr_repository_policy", wantErr: false},
|
||||
{name: "cloudtrail", dirName: "aws_cloudtrail", wantErr: false},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
[
|
||||
{
|
||||
"Id": "testtrailtrail",
|
||||
"Type": "aws_cloudtrail",
|
||||
"Attrs": {
|
||||
"arn": "arn:aws:cloudtrail:eu-west-2:526954929923:trail/testtrailtrail",
|
||||
"cloud_watch_logs_group_arn": "",
|
||||
"cloud_watch_logs_role_arn": "",
|
||||
"enable_log_file_validation": false,
|
||||
"enable_logging": true,
|
||||
"home_region": "eu-west-2",
|
||||
"id": "testtrailtrail",
|
||||
"include_global_service_events": true,
|
||||
"is_multi_region_trail": false,
|
||||
"is_organization_trail": false,
|
||||
"kms_key_id": "",
|
||||
"name": "testtrailtrail",
|
||||
"s3_bucket_name": "testtrailbuckettestestest",
|
||||
"s3_key_prefix": "",
|
||||
"sns_topic_name": ""
|
||||
}
|
||||
}
|
||||
]
|
|
@ -0,0 +1,47 @@
|
|||
{
|
||||
"version": 4,
|
||||
"terraform_version": "0.14.2",
|
||||
"serial": 72,
|
||||
"lineage": "0a405b90-f526-2004-0d4b-f5fd84ca6664",
|
||||
"outputs": {},
|
||||
"resources": [
|
||||
{
|
||||
"mode": "managed",
|
||||
"type": "aws_cloudtrail",
|
||||
"name": "testtrailtrail",
|
||||
"provider": "provider[\"registry.terraform.io/hashicorp/aws\"]",
|
||||
"instances": [
|
||||
{
|
||||
"schema_version": 0,
|
||||
"attributes": {
|
||||
"advanced_event_selector": [],
|
||||
"arn": "arn:aws:cloudtrail:eu-west-2:526954929923:trail/testtrailtrail",
|
||||
"cloud_watch_logs_group_arn": "",
|
||||
"cloud_watch_logs_role_arn": "",
|
||||
"enable_log_file_validation": false,
|
||||
"enable_logging": true,
|
||||
"event_selector": [],
|
||||
"home_region": "eu-west-2",
|
||||
"id": "testtrailtrail",
|
||||
"include_global_service_events": true,
|
||||
"insight_selector": [],
|
||||
"is_multi_region_trail": false,
|
||||
"is_organization_trail": false,
|
||||
"kms_key_id": "",
|
||||
"name": "testtrailtrail",
|
||||
"s3_bucket_name": "testtrailbuckettestestest",
|
||||
"s3_key_prefix": "",
|
||||
"sns_topic_name": "",
|
||||
"tags": null,
|
||||
"tags_all": {}
|
||||
},
|
||||
"sensitive_attributes": [],
|
||||
"private": "bnVsbA==",
|
||||
"dependencies": [
|
||||
"aws_s3_bucket.testtrailbuckettestestest"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package aws
|
||||
|
||||
import (
|
||||
"github.com/snyk/driftctl/enumeration/resource"
|
||||
dctlresource "github.com/snyk/driftctl/pkg/resource"
|
||||
)
|
||||
|
||||
const AwsCloudtrailResourceType = "aws_cloudtrail"
|
||||
|
||||
func initAwsCloudtrailMetaData(resourceSchemaRepository dctlresource.SchemaRepositoryInterface) {
|
||||
/*resourceSchemaRepository.SetNormalizeFunc(AwsCloudfrontDistributionResourceType, func(res *resource.Resource) {
|
||||
val := res.Attrs
|
||||
})*/
|
||||
resourceSchemaRepository.SetFlags(AwsCloudfrontDistributionResourceType, resource.FlagDeepMode)
|
||||
|
||||
}
|
|
@ -69,4 +69,5 @@ func InitResourcesMetadata(resourceSchemaRepository resource.SchemaRepositoryInt
|
|||
initAwsRDSClusterMetaData(resourceSchemaRepository)
|
||||
initAwsCloudformationStackMetaData(resourceSchemaRepository)
|
||||
initAwsAppAutoscalingTargetMetaData(resourceSchemaRepository)
|
||||
initAwsCloudtrailMetaData(resourceSchemaRepository)
|
||||
}
|
||||
|
|
|
@ -177,6 +177,7 @@ var supportedTypes = map[string]ResourceTypeMeta{
|
|||
"aws_launch_configuration": {},
|
||||
"aws_elb": {},
|
||||
"aws_elasticache_cluster": {},
|
||||
"aws_cloudtrail": {},
|
||||
|
||||
"github_branch_protection": {},
|
||||
"github_membership": {},
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
package aws
|
||||
|
||||
import (
|
||||
"github.com/aws/aws-sdk-go/service/cloudtrail/cloudtrailiface"
|
||||
)
|
||||
|
||||
type FakeCloudtrail interface {
|
||||
cloudtrailiface.CloudTrailAPI
|
||||
}
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue