Implement "network" using SecurityGroups

Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
This commit is contained in:
Nicolas De Loof 2020-05-05 14:45:34 +02:00
parent 6febf68748
commit 1889d04d83
No known key found for this signature in database
GPG Key ID: 9858809D6F8F6E7E
3 changed files with 63 additions and 21 deletions

View File

@ -8,6 +8,7 @@ import (
const ( const (
ProjectTag = "com.docker.compose.project" ProjectTag = "com.docker.compose.project"
NetworkTag = "com.docker.compose.network"
) )
func NewClient(profile string, cluster string, region string) (compose.API, error) { func NewClient(profile string, cluster string, region string) (compose.API, error) {

View File

@ -6,14 +6,16 @@ import (
"fmt" "fmt"
"strings" "strings"
ecsapi "github.com/aws/aws-sdk-go/service/ecs"
cloudmapapi "github.com/aws/aws-sdk-go/service/servicediscovery" cloudmapapi "github.com/aws/aws-sdk-go/service/servicediscovery"
ecsapi "github.com/aws/aws-sdk-go/service/ecs"
"github.com/awslabs/goformation/v4/cloudformation" "github.com/awslabs/goformation/v4/cloudformation"
"github.com/awslabs/goformation/v4/cloudformation/ec2" "github.com/awslabs/goformation/v4/cloudformation/ec2"
"github.com/awslabs/goformation/v4/cloudformation/ecs" "github.com/awslabs/goformation/v4/cloudformation/ecs"
"github.com/awslabs/goformation/v4/cloudformation/iam" "github.com/awslabs/goformation/v4/cloudformation/iam"
"github.com/awslabs/goformation/v4/cloudformation/logs" "github.com/awslabs/goformation/v4/cloudformation/logs"
cloudmap "github.com/awslabs/goformation/v4/cloudformation/servicediscovery" cloudmap "github.com/awslabs/goformation/v4/cloudformation/servicediscovery"
"github.com/awslabs/goformation/v4/cloudformation/tags"
"github.com/docker/ecs-plugin/pkg/compose" "github.com/docker/ecs-plugin/pkg/compose"
) )
@ -29,25 +31,9 @@ func (c client) Convert(ctx context.Context, project *compose.Project) (*cloudfo
return nil, err return nil, err
} }
var ingresses = []ec2.SecurityGroup_Ingress{} for net := range project.Networks {
for _, service := range project.Services { name, resource := convertNetwork(project, net, vpc)
for _, port := range service.Ports { template.Resources[name] = resource
ingresses = append(ingresses, ec2.SecurityGroup_Ingress{
CidrIp: "0.0.0.0/0",
Description: fmt.Sprintf("%s:%d/%s", service.Name, port.Target, port.Protocol),
FromPort: int(port.Target),
IpProtocol: strings.ToUpper(port.Protocol),
ToPort: int(port.Target),
})
}
}
securityGroup := fmt.Sprintf("%s Security Group", project.Name)
template.Resources["SecurityGroup"] = &ec2.SecurityGroup{
GroupDescription: securityGroup,
GroupName: securityGroup,
SecurityGroupIngress: ingresses,
VpcId: vpc,
} }
logGroup := fmt.Sprintf("/docker-compose/%s", project.Name) logGroup := fmt.Sprintf("/docker-compose/%s", project.Name)
@ -104,6 +90,12 @@ func (c client) Convert(ctx context.Context, project *compose.Project) (*cloudfo
}, },
} }
serviceSecurityGroups := []string{}
for net := range service.Networks {
logicalName := networkResourceName(project, net)
serviceSecurityGroups = append(serviceSecurityGroups, cloudformation.Ref(logicalName))
}
template.Resources[fmt.Sprintf("%sService", service.Name)] = &ecs.Service{ template.Resources[fmt.Sprintf("%sService", service.Name)] = &ecs.Service{
Cluster: c.Cluster, Cluster: c.Cluster,
DesiredCount: 1, DesiredCount: 1,
@ -111,7 +103,7 @@ func (c client) Convert(ctx context.Context, project *compose.Project) (*cloudfo
NetworkConfiguration: &ecs.Service_NetworkConfiguration{ NetworkConfiguration: &ecs.Service_NetworkConfiguration{
AwsvpcConfiguration: &ecs.Service_AwsVpcConfiguration{ AwsvpcConfiguration: &ecs.Service_AwsVpcConfiguration{
AssignPublicIp: ecsapi.AssignPublicIpEnabled, AssignPublicIp: ecsapi.AssignPublicIpEnabled,
SecurityGroups: []string{cloudformation.Ref("SecurityGroup")}, SecurityGroups: serviceSecurityGroups,
Subnets: subnets, Subnets: subnets,
}, },
}, },
@ -128,6 +120,46 @@ func (c client) Convert(ctx context.Context, project *compose.Project) (*cloudfo
return template, nil return template, nil
} }
func convertNetwork(project *compose.Project, net string, vpc string) (string, cloudformation.Resource) {
var ingresses []ec2.SecurityGroup_Ingress
for _, service := range project.Services {
if _, ok := service.Networks[net]; ok {
for _, port := range service.Ports {
ingresses = append(ingresses, ec2.SecurityGroup_Ingress{
CidrIp: "0.0.0.0/0",
Description: fmt.Sprintf("%s:%d/%s", service.Name, port.Target, port.Protocol),
FromPort: int(port.Target),
IpProtocol: strings.ToUpper(port.Protocol),
ToPort: int(port.Target),
})
}
}
}
securityGroup := networkResourceName(project, net)
resource := &ec2.SecurityGroup{
GroupDescription: fmt.Sprintf("%s %s Security Group", project.Name, net),
GroupName: securityGroup,
SecurityGroupIngress: ingresses,
VpcId: vpc,
Tags: []tags.Tag{
{
Key: ProjectTag,
Value: project.Name,
},
{
Key: NetworkTag,
Value: net,
},
},
}
return securityGroup, resource
}
func networkResourceName(project *compose.Project, network string) string {
return fmt.Sprintf("%s%sNetwork", project.Name, strings.Title(network))
}
func (c client) GetVPC(ctx context.Context, project *compose.Project) (string, error) { func (c client) GetVPC(ctx context.Context, project *compose.Project) (string, error) {
//check compose file for the default external network //check compose file for the default external network
if net, ok := project.Networks["default"]; ok { if net, ok := project.Networks["default"]; ok {

View File

@ -15,6 +15,15 @@ func (c *client) Validate(project *compose.Project) error {
} }
} }
for i, service := range project.Services {
if len(service.Networks) == 0 {
// Service without explicit network attachment are implicitly exposed on default network
// FIXME move this to compose-go
service.Networks = map[string]*types.ServiceNetworkConfig{"default": nil}
project.Services[i] = service
}
}
// Here we can check for incompatible attributes, inject sane defaults, etc // Here we can check for incompatible attributes, inject sane defaults, etc
return nil return nil
} }