feat: add aws_ebs_encryption_by_default

main
sundowndev-snyk 2022-03-28 17:07:02 +04:00
parent 7e4d53ee3f
commit b08c6d55ef
No known key found for this signature in database
GPG Key ID: A4A2BE47AC4C6A68
22 changed files with 172297 additions and 29 deletions

View File

@ -123,6 +123,7 @@ func (d DriftCTL) Run() (*analyser.Analysis, error) {
middlewares.NewAwsApiGatewayRestApiPolicyExpander(d.resourceFactory),
middlewares.NewAwsConsoleApiGatewayGatewayResponse(),
middlewares.NewAwsApiGatewayDomainNamesReconciler(),
middlewares.NewAwsEbsEncryptionByDefaultReconciler(d.resourceFactory),
middlewares.NewGoogleIAMBindingTransformer(d.resourceFactory),
middlewares.NewGoogleIAMPolicyTransformer(d.resourceFactory),

View File

@ -192,6 +192,7 @@ func TestTerraformStateReader_AWS_Resources(t *testing.T) {
{name: "App autoscaling scheduled action", dirName: "aws_appautoscaling_scheduled_action", wantErr: false},
{name: "Launch template", dirName: "aws_launch_template", wantErr: false},
{name: "Launch configuration", dirName: "aws_launch_configuration", wantErr: false},
{name: "EBS encryption by default", dirName: "aws_ebs_encryption_by_default", wantErr: false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {

View File

@ -0,0 +1,10 @@
[
{
"Id": "terraform-20220328091515068500000001",
"Type": "aws_ebs_encryption_by_default",
"Attrs": {
"enabled": true,
"id": "terraform-20220328091515068500000001"
}
}
]

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,26 @@
{
"version": 4,
"terraform_version": "1.0.0",
"serial": 450,
"lineage": "9566e18d-6080-4aa8-e9a6-4c38905cf68f",
"outputs": {},
"resources": [
{
"mode": "managed",
"type": "aws_ebs_encryption_by_default",
"name": "example",
"provider": "provider[\"registry.terraform.io/hashicorp/aws\"]",
"instances": [
{
"schema_version": 0,
"attributes": {
"enabled": true,
"id": "terraform-20220328091515068500000001"
},
"sensitive_attributes": [],
"private": "bnVsbA=="
}
]
}
]
}

View File

@ -0,0 +1,59 @@
package middlewares
import (
"github.com/snyk/driftctl/pkg/resource"
"github.com/snyk/driftctl/pkg/resource/aws"
)
// AwsEbsEncryptionByDefaultReconciler is a middleware that create remote equivalent
// "aws_ebs_encryption_by_default" resources from state resources.
// Since we don't have an ID for remote resources of this type.
type AwsEbsEncryptionByDefaultReconciler struct {
resourceFactory resource.ResourceFactory
}
func NewAwsEbsEncryptionByDefaultReconciler(resourceFactory resource.ResourceFactory) AwsEbsEncryptionByDefaultReconciler {
return AwsEbsEncryptionByDefaultReconciler{
resourceFactory: resourceFactory,
}
}
func (m AwsEbsEncryptionByDefaultReconciler) Execute(remoteResources, resourcesFromState *[]*resource.Resource) error {
newStateResources := make([]*resource.Resource, 0)
newRemoteResources := make([]*resource.Resource, 0)
var defaultEbsEncryption *resource.Resource
for _, res := range *remoteResources {
// Ignore all resources other than aws_ebs_encryption_by_default
if res.ResourceType() != aws.AwsEbsEncryptionByDefaultResourceType {
newRemoteResources = append(newRemoteResources, res)
continue
}
defaultEbsEncryption = res
break
}
for _, res := range *resourcesFromState {
newStateResources = append(newStateResources, res)
// Ignore all resources other than aws_ebs_encryption_by_default
if res.ResourceType() != aws.AwsEbsEncryptionByDefaultResourceType {
continue
}
// Create the same resource in remote but with the remote attributes, so we can compare it with the state resource
newRemoteResources = append(newRemoteResources, m.resourceFactory.CreateAbstractResource(
res.ResourceType(),
res.ResourceId(),
map[string]interface{}{
"id": res.ResourceId(),
"enabled": *defaultEbsEncryption.Attributes().GetBool("enabled"),
},
))
}
*resourcesFromState = newStateResources
*remoteResources = newRemoteResources
return nil
}

View File

@ -0,0 +1,112 @@
package middlewares
import (
"strings"
"testing"
"github.com/aws/aws-sdk-go/aws/awsutil"
"github.com/r3labs/diff/v2"
"github.com/snyk/driftctl/pkg/terraform"
"github.com/snyk/driftctl/pkg/resource"
"github.com/snyk/driftctl/pkg/resource/aws"
)
func TestAwsEbsEncryptionByDefaultReconciler_Execute(t *testing.T) {
tests := []struct {
name string
mocks func(*terraform.MockResourceFactory)
remoteResources []*resource.Resource
resourcesFromState []*resource.Resource
expected []*resource.Resource
}{
{
"test encryption by default is managed",
func(factory *terraform.MockResourceFactory) {
factory.On("CreateAbstractResource",
aws.AwsEbsEncryptionByDefaultResourceType,
"terraform-20220328091515068500000001",
map[string]interface{}{
"id": "terraform-20220328091515068500000001",
"enabled": true,
}).Return(&resource.Resource{
Id: "terraform-20220328091515068500000001",
Type: aws.AwsEbsEncryptionByDefaultResourceType,
Attrs: &resource.Attributes{
"id": "terraform-20220328091515068500000001",
"enabled": true,
},
}).Once()
},
[]*resource.Resource{
{
Id: "bucket-1",
Type: aws.AwsS3BucketResourceType,
Attrs: &resource.Attributes{},
},
{
Id: "test-encryption",
Type: aws.AwsEbsEncryptionByDefaultResourceType,
Attrs: &resource.Attributes{
"enabled": true,
},
},
},
[]*resource.Resource{
{
Id: "bucket-1",
Type: aws.AwsS3BucketResourceType,
Attrs: &resource.Attributes{},
},
{
Id: "terraform-20220328091515068500000001",
Type: aws.AwsEbsEncryptionByDefaultResourceType,
Attrs: &resource.Attributes{
"id": "terraform-20220328091515068500000001",
"enabled": true,
},
},
},
[]*resource.Resource{
{
Id: "bucket-1",
Type: aws.AwsS3BucketResourceType,
Attrs: &resource.Attributes{},
},
{
Id: "terraform-20220328091515068500000001",
Type: aws.AwsEbsEncryptionByDefaultResourceType,
Attrs: &resource.Attributes{
"id": "terraform-20220328091515068500000001",
"enabled": true,
},
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
factory := &terraform.MockResourceFactory{}
if tt.mocks != nil {
tt.mocks(factory)
}
m := NewAwsEbsEncryptionByDefaultReconciler(factory)
err := m.Execute(&tt.remoteResources, &tt.resourcesFromState)
if err != nil {
t.Fatal(err)
}
changelog, err := diff.Diff(tt.remoteResources, tt.expected)
if err != nil {
t.Fatal(err)
}
if len(changelog) > 0 {
for _, change := range changelog {
t.Errorf("%s got = %v, want %v", strings.Join(change.Path, "."), awsutil.Prettify(change.From), awsutil.Prettify(change.To))
}
}
})
}
}

View File

@ -0,0 +1,46 @@
package aws
import (
"github.com/snyk/driftctl/pkg/remote/aws/repository"
remoteerror "github.com/snyk/driftctl/pkg/remote/error"
"github.com/snyk/driftctl/pkg/resource"
"github.com/snyk/driftctl/pkg/resource/aws"
)
type EC2EbsEncryptionByDefaultEnumerator struct {
repository repository.EC2Repository
factory resource.ResourceFactory
}
func NewEC2EbsEncryptionByDefaultEnumerator(repo repository.EC2Repository, factory resource.ResourceFactory) *EC2EbsEncryptionByDefaultEnumerator {
return &EC2EbsEncryptionByDefaultEnumerator{
repository: repo,
factory: factory,
}
}
func (e *EC2EbsEncryptionByDefaultEnumerator) SupportedType() resource.ResourceType {
return aws.AwsEbsEncryptionByDefaultResourceType
}
func (e *EC2EbsEncryptionByDefaultEnumerator) Enumerate() ([]*resource.Resource, error) {
enabled, err := e.repository.IsEbsEncryptionEnabledByDefault()
if err != nil {
return nil, remoteerror.NewResourceListingError(err, string(e.SupportedType()))
}
results := make([]*resource.Resource, 0)
results = append(
results,
e.factory.CreateAbstractResource(
string(e.SupportedType()),
"ebs_encryption_default",
map[string]interface{}{
"enabled": enabled,
},
),
)
return results, err
}

View File

@ -116,6 +116,9 @@ func Init(version string, alerter *alerter.Alerter,
remoteLibrary.AddDetailsFetcher(aws.AwsRouteResourceType, common.NewGenericDetailsFetcher(aws.AwsRouteResourceType, provider, deserializer))
remoteLibrary.AddEnumerator(NewVPCSecurityGroupRuleEnumerator(ec2repository, factory))
remoteLibrary.AddDetailsFetcher(aws.AwsSecurityGroupRuleResourceType, common.NewGenericDetailsFetcher(aws.AwsSecurityGroupRuleResourceType, provider, deserializer))
remoteLibrary.AddEnumerator(NewLaunchTemplateEnumerator(ec2repository, factory))
remoteLibrary.AddEnumerator(NewEC2EbsEncryptionByDefaultEnumerator(ec2repository, factory))
remoteLibrary.AddDetailsFetcher(aws.AwsEbsEncryptionByDefaultResourceType, common.NewGenericDetailsFetcher(aws.AwsEbsEncryptionByDefaultResourceType, provider, deserializer))
remoteLibrary.AddEnumerator(NewKMSKeyEnumerator(kmsRepository, factory))
remoteLibrary.AddDetailsFetcher(aws.AwsKmsKeyResourceType, common.NewGenericDetailsFetcher(aws.AwsKmsKeyResourceType, provider, deserializer))
@ -224,7 +227,6 @@ func Init(version string, alerter *alerter.Alerter,
remoteLibrary.AddEnumerator(NewAppAutoscalingScheduledActionEnumerator(appAutoScalingRepository, factory))
remoteLibrary.AddEnumerator(NewLaunchTemplateEnumerator(ec2repository, factory))
remoteLibrary.AddDetailsFetcher(aws.AwsLaunchTemplateResourceType, common.NewGenericDetailsFetcher(aws.AwsLaunchTemplateResourceType, provider, deserializer))
remoteLibrary.AddEnumerator(NewLaunchConfigurationEnumerator(autoscalingRepository, factory))

View File

@ -24,6 +24,7 @@ type EC2Repository interface {
ListAllSecurityGroups() ([]*ec2.SecurityGroup, []*ec2.SecurityGroup, error)
ListAllNetworkACLs() ([]*ec2.NetworkAcl, error)
DescribeLaunchTemplates() ([]*ec2.LaunchTemplate, error)
IsEbsEncryptionEnabledByDefault() (bool, error)
}
type ec2Repository struct {
@ -391,3 +392,17 @@ func (r *ec2Repository) DescribeLaunchTemplates() ([]*ec2.LaunchTemplate, error)
r.cache.Put(cacheKey, resp.LaunchTemplates)
return resp.LaunchTemplates, nil
}
func (r *ec2Repository) IsEbsEncryptionEnabledByDefault() (bool, error) {
if v := r.cache.Get("ec2IsEbsEncryptionEnabledByDefault"); v != nil {
return v.(bool), nil
}
input := &ec2.GetEbsEncryptionByDefaultInput{}
resp, err := r.client.GetEbsEncryptionByDefault(input)
if err != nil {
return false, err
}
r.cache.Put("ec2IsEbsEncryptionEnabledByDefault", *resp.EbsEncryptionByDefault)
return *resp.EbsEncryptionByDefault, err
}

View File

@ -1355,3 +1355,75 @@ func Test_ec2Repository_DescribeLaunchTemplates(t *testing.T) {
})
}
}
func Test_ec2Repository_IsEbsEncryptionEnabledByDefault(t *testing.T) {
testErr := errors.New("test")
tests := []struct {
name string
mocks func(client *awstest.MockFakeEC2, store *cache.MockCache)
want bool
wantErr error
}{
{
name: "test that encryption enabled by default",
mocks: func(client *awstest.MockFakeEC2, store *cache.MockCache) {
store.On("Get", "ec2IsEbsEncryptionEnabledByDefault").
Return(nil).
Once()
client.On("GetEbsEncryptionByDefault",
&ec2.GetEbsEncryptionByDefaultInput{},
).Return(&ec2.GetEbsEncryptionByDefaultOutput{
EbsEncryptionByDefault: aws.Bool(true),
}, nil).Once()
store.On("Put", "ec2IsEbsEncryptionEnabledByDefault", true).
Return(false).
Once()
},
want: true,
},
{
name: "test that encryption enabled by default (cached)",
mocks: func(client *awstest.MockFakeEC2, store *cache.MockCache) {
store.On("Get", "ec2IsEbsEncryptionEnabledByDefault").
Return(false).
Once()
},
want: false,
},
{
name: "error while getting default encryption value",
mocks: func(client *awstest.MockFakeEC2, store *cache.MockCache) {
store.On("Get", "ec2IsEbsEncryptionEnabledByDefault").
Return(nil).
Once()
client.On("GetEbsEncryptionByDefault",
&ec2.GetEbsEncryptionByDefaultInput{},
).Return(nil, testErr).Once()
},
wantErr: testErr,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
store := &cache.MockCache{}
client := &awstest.MockFakeEC2{}
tt.mocks(client, store)
r := &ec2Repository{
client: client,
cache: store,
}
got, err := r.IsEbsEncryptionEnabledByDefault()
assert.Equal(t, tt.wantErr, err)
assert.Equal(t, tt.want, got)
client.AssertExpectations(t)
store.AssertExpectations(t)
})
}
}

View File

@ -1,4 +1,4 @@
// Code generated by mockery v2.8.0. DO NOT EDIT.
// Code generated by mockery v2.10.0. DO NOT EDIT.
package repository
@ -12,29 +12,6 @@ type MockEC2Repository struct {
mock.Mock
}
// DescribeLaunchTemplateVersions provides a mock function with given fields: _a0
func (_m *MockEC2Repository) DescribeLaunchTemplateVersions(_a0 *ec2.LaunchTemplate) ([]*ec2.LaunchTemplateVersion, error) {
ret := _m.Called(_a0)
var r0 []*ec2.LaunchTemplateVersion
if rf, ok := ret.Get(0).(func(*ec2.LaunchTemplate) []*ec2.LaunchTemplateVersion); ok {
r0 = rf(_a0)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]*ec2.LaunchTemplateVersion)
}
}
var r1 error
if rf, ok := ret.Get(1).(func(*ec2.LaunchTemplate) error); ok {
r1 = rf(_a0)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// DescribeLaunchTemplates provides a mock function with given fields:
func (_m *MockEC2Repository) DescribeLaunchTemplates() ([]*ec2.LaunchTemplate, error) {
ret := _m.Called()
@ -58,6 +35,27 @@ func (_m *MockEC2Repository) DescribeLaunchTemplates() ([]*ec2.LaunchTemplate, e
return r0, r1
}
// IsEbsEncryptionEnabledByDefault provides a mock function with given fields:
func (_m *MockEC2Repository) IsEbsEncryptionEnabledByDefault() (bool, error) {
ret := _m.Called()
var r0 bool
if rf, ok := ret.Get(0).(func() bool); ok {
r0 = rf()
} else {
r0 = ret.Get(0).(bool)
}
var r1 error
if rf, ok := ret.Get(1).(func() error); ok {
r1 = rf()
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// ListAllAddresses provides a mock function with given fields:
func (_m *MockEC2Repository) ListAllAddresses() ([]*ec2.Address, error) {
ret := _m.Called()

View File

@ -2814,3 +2814,90 @@ func TestEC2LaunchTemplate(t *testing.T) {
})
}
}
func TestEC2EbsEncryptionByDefault(t *testing.T) {
tests := []struct {
test string
dirName string
mocks func(*repository.MockEC2Repository, *mocks.AlerterInterface)
wantErr error
}{
{
test: "no encryption by default resource",
dirName: "aws_ebs_encryption_by_default_list",
mocks: func(repository *repository.MockEC2Repository, alerter *mocks.AlerterInterface) {
repository.On("IsEbsEncryptionEnabledByDefault").Return(false, nil)
},
},
{
test: "cannot list encryption by default resources",
dirName: "aws_ebs_encryption_by_default_error",
mocks: func(repository *repository.MockEC2Repository, alerter *mocks.AlerterInterface) {
awsError := awserr.NewRequestFailure(awserr.New("AccessDeniedException", "", errors.New("")), 403, "")
repository.On("IsEbsEncryptionEnabledByDefault").Return(false, awsError)
alerter.On("SendAlert", resourceaws.AwsEbsEncryptionByDefaultResourceType, alerts.NewRemoteAccessDeniedAlert(common.RemoteAWSTerraform, remoteerr.NewResourceListingErrorWithType(awsError, resourceaws.AwsEbsEncryptionByDefaultResourceType, resourceaws.AwsEbsEncryptionByDefaultResourceType), alerts.EnumerationPhase)).Return()
},
wantErr: nil,
},
}
schemaRepository := testresource.InitFakeSchemaRepository("aws", "3.19.0")
resourceaws.InitResourcesMetadata(schemaRepository)
factory := terraform.NewTerraformResourceFactory(schemaRepository)
deserializer := resource.NewDeserializer(factory)
for _, c := range tests {
t.Run(c.test, func(tt *testing.T) {
shouldUpdate := c.dirName == *goldenfile.Update
sess := session.Must(session.NewSessionWithOptions(session.Options{
SharedConfigState: session.SharedConfigEnable,
}))
scanOptions := ScannerOptions{Deep: true}
providerLibrary := terraform.NewProviderLibrary()
remoteLibrary := common.NewRemoteLibrary()
// Initialize mocks
alerter := &mocks.AlerterInterface{}
fakeRepo := &repository.MockEC2Repository{}
c.mocks(fakeRepo, alerter)
var repo repository.EC2Repository = fakeRepo
providerVersion := "3.19.0"
realProvider, err := terraform2.InitTestAwsProvider(providerLibrary, providerVersion)
if err != nil {
t.Fatal(err)
}
provider := terraform2.NewFakeTerraformProvider(realProvider)
provider.WithResponse(c.dirName)
// Replace mock by real resources if we are in update mode
if shouldUpdate {
err := realProvider.Init()
if err != nil {
t.Fatal(err)
}
provider.ShouldUpdate()
repo = repository.NewEC2Repository(sess, cache.New(0))
}
remoteLibrary.AddEnumerator(aws.NewEC2EbsEncryptionByDefaultEnumerator(repo, factory))
remoteLibrary.AddDetailsFetcher(resourceaws.AwsEbsEncryptionByDefaultResourceType, common.NewGenericDetailsFetcher(resourceaws.AwsEbsEncryptionByDefaultResourceType, provider, deserializer))
testFilter := &filter.MockFilter{}
testFilter.On("IsTypeIgnored", mock.Anything).Return(false)
s := NewScanner(remoteLibrary, alerter, scanOptions, testFilter)
got, err := s.Resources()
assert.Equal(tt, err, c.wantErr)
if err != nil {
return
}
test.TestAgainstGoldenFile(got, resourceaws.AwsEbsEncryptionByDefaultResourceType, c.dirName, provider, deserializer, shouldUpdate, tt)
alerter.AssertExpectations(tt)
fakeRepo.AssertExpectations(tt)
})
}
}

View File

@ -0,0 +1,5 @@
{
"Typ": "WyJvYmplY3QiLHsiZW5hYmxlZCI6ImJvb2wiLCJpZCI6InN0cmluZyJ9XQ==",
"Val": "eyJlbmFibGVkIjpmYWxzZSwiaWQiOiJlYnNfZW5jcnlwdGlvbl9kZWZhdWx0In0=",
"Err": null
}

View File

@ -0,0 +1,6 @@
[
{
"enabled": false,
"id": "ebs_encryption_default"
}
]

View File

@ -0,0 +1,9 @@
package aws
import "github.com/snyk/driftctl/pkg/resource"
const AwsEbsEncryptionByDefaultResourceType = "aws_ebs_encryption_by_default"
func initAwsEbsEncryptionByDefaultMetaData(resourceSchemaRepository resource.SchemaRepositoryInterface) {
resourceSchemaRepository.SetFlags(AwsEbsEncryptionByDefaultResourceType, resource.FlagDeepMode)
}

View File

@ -0,0 +1,30 @@
package aws_test
import (
"testing"
"github.com/snyk/driftctl/test"
"github.com/snyk/driftctl/test/acceptance"
)
func TestAcc_Aws_EbsEncryptionByDefault(t *testing.T) {
acceptance.Run(t, acceptance.AccTestCase{
TerraformVersion: "0.15.5",
Paths: []string{"./testdata/acc/aws_ebs_encryption_by_default"},
Args: []string{"scan", "--deep"},
Checks: []acceptance.AccCheck{
{
Env: map[string]string{
"AWS_REGION": "us-east-1",
},
Check: func(result *test.ScanResult, stdout string, err error) {
if err != nil {
t.Fatal(err)
}
result.AssertInfrastructureIsInSync()
result.AssertManagedCount(1)
},
},
},
})
}

View File

@ -65,4 +65,5 @@ func InitResourcesMetadata(resourceSchemaRepository resource.SchemaRepositoryInt
initAwsLaunchTemplateMetaData(resourceSchemaRepository)
initAwsApiGatewayV2ModelMetaData(resourceSchemaRepository)
initAwsApiGatewayV2MappingMetaData(resourceSchemaRepository)
initAwsEbsEncryptionByDefaultMetaData(resourceSchemaRepository)
}

View File

@ -0,0 +1,2 @@
*
!aws_ebs_encryption_by_default

View File

@ -0,0 +1,21 @@
# This file is maintained automatically by "terraform init".
# Manual edits may be lost in future updates.
provider "registry.terraform.io/hashicorp/aws" {
version = "4.8.0"
hashes = [
"h1:T9Typ5V+dDwecG9USCLbW4oayxN3cxEGsG+OJzzjRgY=",
"zh:16cbdbc03ad13358d12433e645e2ab5a615e3a3662a74e3c317267c9377713d8",
"zh:1d813c5e6c21fe370652495e29f783db4e65037f913ff0d53d28515c36fbb70a",
"zh:31ad8282e31d0fac62e96fc2321a68ad4b92ab90f560be5f875d1b01a493e491",
"zh:5099a9e699784cabb5686d2cb52ca910f9c697e977c654ecedd196e838387623",
"zh:5758cbb813091db8573f27bba37c48f63ba95f2104f3bc49f13131e3c305b848",
"zh:67ea77fb00bf0a09e712f5259a7acb494ce503a34809b7919996744fd92e3312",
"zh:72c87be5d1f7917d4281c14a3335a9ec3cd57bf63d95a440faa7035248083dcd",
"zh:79005154b9f5eccc1580e0eb803f0dfee68ba856703ef6489719cb014a3c2b18",
"zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425",
"zh:d27f9a8b5b30883a3e45f77506391524df0c66a76c3bc71f7236c3fc81d0597d",
"zh:e2985563dc652cf9b10420bc62f0a710308ef5c31e46b94c8ea10b8f27fa1ef3",
"zh:f11bb34ee0dad4bc865db51e7e299a4f030c5e9f6b6080d611797cc99deeb40a",
]
}

View File

@ -0,0 +1,7 @@
provider "aws" {
region = "us-east-1"
}
resource "aws_ebs_encryption_by_default" "test-encryption" {
enabled = true
}

View File

@ -21,10 +21,11 @@ var supportedTypes = map[string]ResourceTypeMeta{
// VPC are used by aws_internet_gateway to determine if internet gateway is the default one in middleware
"aws_internet_gateway",
}},
"aws_dynamodb_table": {},
"aws_ebs_snapshot": {},
"aws_ebs_volume": {},
"aws_ecr_repository": {},
"aws_dynamodb_table": {},
"aws_ebs_snapshot": {},
"aws_ebs_volume": {},
"aws_ebs_encryption_by_default": {},
"aws_ecr_repository": {},
"aws_eip": {children: []ResourceType{
"aws_eip_association",
}},