Skip to content
This repository has been archived by the owner on Nov 27, 2023. It is now read-only.

Only consider public subnets #1064

Merged
merged 1 commit into from
Dec 15, 2020
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
1 change: 1 addition & 0 deletions ecs/aws.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ type API interface {
CheckVPC(ctx context.Context, vpcID string) error
GetDefaultVPC(ctx context.Context) (string, error)
GetSubNets(ctx context.Context, vpcID string) ([]awsResource, error)
IsPublicSubnet(ctx context.Context, vpcID string, subNetID string) (bool, error)
GetRoleArn(ctx context.Context, name string) (string, error)
StackExists(ctx context.Context, name string) (bool, error)
CreateStack(ctx context.Context, name string, region string, template []byte) error
Expand Down
18 changes: 15 additions & 3 deletions ecs/awsResources.go
Original file line number Diff line number Diff line change
Expand Up @@ -185,10 +185,22 @@ func (b *ecsAPIService) parseVPCExtension(ctx context.Context, project *types.Pr
if err != nil {
return "", nil, err
}
if len(subNets) < 2 {
return "", nil, fmt.Errorf("VPC %s should have at least 2 associated subnets in different availability zones", vpc)

var publicSubNets []awsResource
for _, subNet := range subNets {
isPublic, err := b.aws.IsPublicSubnet(ctx, vpc, subNet.ID())
if err != nil {
return "", nil, err
}
if isPublic {
publicSubNets = append(publicSubNets, subNet)
}
}

if len(publicSubNets) < 2 {
return "", nil, fmt.Errorf("VPC %s should have at least 2 associated public subnets in different availability zones", vpc)
}
return vpc, subNets, nil
return vpc, publicSubNets, nil
}

func (b *ecsAPIService) parseLoadBalancerExtension(ctx context.Context, project *types.Project) (awsResource, string, error) {
Expand Down
18 changes: 17 additions & 1 deletion ecs/aws_mock.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions ecs/cloudformation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -591,6 +591,8 @@ func useDefaultVPC(m *MockAPIMockRecorder) {
existingAWSResource{id: "subnet1"},
existingAWSResource{id: "subnet2"},
}, nil)
m.IsPublicSubnet(gomock.Any(), "subnet1").Return(true, nil)
m.IsPublicSubnet(gomock.Any(), "subnet2").Return(true, nil)
}

func useGPU(m *MockAPIMockRecorder) {
Expand Down
31 changes: 31 additions & 0 deletions ecs/sdk.go
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,37 @@ func (s sdk) GetSubNets(ctx context.Context, vpcID string) ([]awsResource, error
return ids, nil
}

func (s sdk) IsPublicSubnet(ctx context.Context, vpcID string, subNetID string) (bool, error) {
tables, err := s.EC2.DescribeRouteTablesWithContext(ctx, &ec2.DescribeRouteTablesInput{
Filters: []*ec2.Filter{
{
Name: aws.String("association.subnet-id"),
Values: []*string{aws.String(subNetID)},
},
},
})
if err != nil {
return false, err
}
if len(tables.RouteTables) == 0 {
// If a subnet is not explicitly associated with any route table, it is implicitly associated with the main route table.
// https://docs.aws.amazon.com/cli/latest/reference/ec2/describe-route-tables.html
return true, nil
}
for _, routeTable := range tables.RouteTables {
for _, route := range routeTable.Routes {
if aws.StringValue(route.State) != "active" {
continue
}
if strings.HasPrefix(aws.StringValue(route.GatewayId), "igw-") {
// Connected to an internet Gateway
return true, nil
}
}
}
return false, nil
}

func (s sdk) GetRoleArn(ctx context.Context, name string) (string, error) {
role, err := s.IAM.GetRoleWithContext(ctx, &iam.GetRoleInput{
RoleName: aws.String(name),
Expand Down