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

ECS: Redid security group generation for LBs #2215

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
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
31 changes: 28 additions & 3 deletions ecs/awsResources.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ func (r *awsResources) serviceSecurityGroups(service types.ServiceConfig) []stri
for net := range service.Networks {
groups = append(groups, r.securityGroups[net])
}
if len(service.Ports) > 0 {
groups = append(groups, r.securityGroups[serviceIngressSecGroupName(service.Name, false)])
}
return groups
}

Expand Down Expand Up @@ -330,6 +333,7 @@ func (b *ecsAPIService) ensureCluster(r *awsResources, project *types.Project, t

func (b *ecsAPIService) ensureNetworks(r *awsResources, project *types.Project, template *cloudformation.Template) {
if r.securityGroups == nil {
// TODO NITZ change the size hint?
r.securityGroups = make(map[string]string, len(project.Networks))
}
for name, net := range project.Networks {
Expand All @@ -353,6 +357,27 @@ func (b *ecsAPIService) ensureNetworks(r *awsResources, project *types.Project,

r.securityGroups[name] = cloudformation.Ref(securityGroup)
}

for _, service := range project.Services {
if len(service.Ports) == 0 {
continue
}
lbSecurityGroup := serviceIngressSecGroupName(service.Name, true)
template.Resources[lbSecurityGroup] = &ec2.SecurityGroup{
GroupDescription: fmt.Sprintf("%s Security Group for service %s ingress, LB side", project.Name, service.Name),
VpcId: r.vpc,
Tags: serviceTags(project, service),
}
r.securityGroups[lbSecurityGroup] = cloudformation.Ref(lbSecurityGroup)

serviceSecurityGroup := serviceIngressSecGroupName(service.Name, false)
template.Resources[serviceSecurityGroup] = &ec2.SecurityGroup{
GroupDescription: fmt.Sprintf("%s Security Group for service %s ingress, Service side", project.Name, service.Name),
VpcId: r.vpc,
Tags: serviceTags(project, service),
}
r.securityGroups[serviceSecurityGroup] = cloudformation.Ref(serviceSecurityGroup)
}
}

func (b *ecsAPIService) ensureVolumes(r *awsResources, project *types.Project, template *cloudformation.Template) error {
Expand Down Expand Up @@ -465,9 +490,9 @@ func (b *ecsAPIService) ensureLoadBalancer(r *awsResources, project *types.Proje

func (r *awsResources) getLoadBalancerSecurityGroups(project *types.Project) []string {
securityGroups := []string{}
for name, network := range project.Networks {
if !network.Internal {
securityGroups = append(securityGroups, r.securityGroups[name])
for _, service := range project.Services {
if len(service.Ports) > 0 {
securityGroups = append(securityGroups, r.securityGroups[serviceIngressSecGroupName(service.Name, true)])
}
}
return securityGroups
Expand Down
38 changes: 34 additions & 4 deletions ecs/cloudformation.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,11 +197,15 @@ func (b *ecsAPIService) createService(project *types.Project, service types.Serv
dependsOn []string
serviceLB []ecs.Service_LoadBalancer
)
for _, port := range service.Ports {
for net := range service.Networks {
b.createIngress(service, net, port, template, resources)
}

for _, port := range service.Ports {
lbSecurityGroupName := serviceIngressSecGroupName(service.Name, true)
serviceSecurityGroupName := serviceIngressSecGroupName(service.Name, false)
// outside to ingress
b.createIngress(service, lbSecurityGroupName, port, template, resources)
// ingress to service
b.createCrossGroupIngress(service, lbSecurityGroupName, serviceSecurityGroupName, port, template, resources)
// TODO attach new secgroup to this service
protocol := strings.ToUpper(port.Protocol)
if resources.loadBalancerType == elbv2.LoadBalancerTypeEnumApplication {
// we don't set Https as a certificate must be specified for HTTPS listeners
Expand Down Expand Up @@ -293,6 +297,22 @@ func (b *ecsAPIService) createIngress(service types.ServiceConfig, net string, p
}
}

func (b *ecsAPIService) createCrossGroupIngress(service types.ServiceConfig, source string, dest string, port types.ServicePortConfig, template *cloudformation.Template, resources awsResources) {
protocol := strings.ToUpper(port.Protocol)
if protocol == "" {
protocol = allProtocols
}
ingress := fmt.Sprintf("%s%d%sIngress", normalizeResourceName(source), port.Target, normalizeResourceName(dest))
template.Resources[ingress] = &ec2.SecurityGroupIngress{
SourceSecurityGroupId: resources.securityGroups[source],
Description: fmt.Sprintf("LB connectivity on %d", port.Target),
GroupId: resources.securityGroups[dest],
FromPort: int(port.Target),
IpProtocol: protocol,
ToPort: int(port.Target),
}
}

func (b *ecsAPIService) createSecret(project *types.Project, name string, s types.SecretConfig, template *cloudformation.Template) error {
if s.External.External {
return nil
Expand Down Expand Up @@ -534,6 +554,16 @@ func networkResourceName(network string) string {
return fmt.Sprintf("%sNetwork", normalizeResourceName(network))
}

func serviceIngressSecGroupName(service string, isLBSide bool) string {
var header string
if isLBSide {
header = "LB"
} else {
header = "Service"
}
return fmt.Sprintf("%s%sIngressSecurityGroup", normalizeResourceName(service), header)
}

func serviceResourceName(service string) string {
return fmt.Sprintf("%sService", normalizeResourceName(service))
}
Expand Down
11 changes: 11 additions & 0 deletions ecs/cloudformation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,17 @@ func TestSimpleConvert(t *testing.T) {
golden.Assert(t, result, expected)
}

func TestSlightlyComplexConvert(t *testing.T) {
bytes, err := ioutil.ReadFile("testdata/input/slightly-complex-service.yaml")
assert.NilError(t, err)
template := convertYaml(t, string(bytes), nil, useDefaultVPC)
resultAsJSON, err := marshall(template, "yaml")
assert.NilError(t, err)
result := fmt.Sprintf("%s\n", string(resultAsJSON))
expected := "slightly-complex-cloudformation-conversion.golden"
golden.Assert(t, result, expected)
}

func TestLogging(t *testing.T) {
template := convertYaml(t, `
services:
Expand Down
8 changes: 8 additions & 0 deletions ecs/testdata/input/slightly-complex-service.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
services:
entrance:
image: nginx
ports:
- "80:80"

sensitive:
image: httpd
56 changes: 45 additions & 11 deletions ecs/testdata/simple-cloudformation-conversion.golden
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,6 @@ Resources:
- Key: com.docker.compose.project
Value: TestSimpleConvert
Type: AWS::ECS::Cluster
Default80Ingress:
Properties:
CidrIp: 0.0.0.0/0
Description: simple:80/tcp on default network
FromPort: 80
GroupId:
Ref: DefaultNetwork
IpProtocol: TCP
ToPort: 80
Type: AWS::EC2::SecurityGroupIngress
DefaultNetwork:
Properties:
GroupDescription: TestSimpleConvert Security Group for default network
Expand All @@ -46,7 +36,7 @@ Resources:
Properties:
Scheme: internet-facing
SecurityGroups:
- Ref: DefaultNetwork
- Ref: SimpleLBIngressSecurityGroup
Subnets:
- subnet1
- subnet2
Expand All @@ -59,6 +49,38 @@ Resources:
Properties:
LogGroupName: /docker-compose/TestSimpleConvert
Type: AWS::Logs::LogGroup
SimpleLBIngressSecurityGroup:
Properties:
GroupDescription: TestSimpleConvert Security Group for service simple ingress,
LB side
Tags:
- Key: com.docker.compose.project
Value: TestSimpleConvert
- Key: com.docker.compose.service
Value: simple
VpcId: vpc-123
Type: AWS::EC2::SecurityGroup
SimpleLBIngressSecurityGroup80Ingress:
Properties:
CidrIp: 0.0.0.0/0
Description: simple:80/tcp on SimpleLBIngressSecurityGroup network
FromPort: 80
GroupId:
Ref: SimpleLBIngressSecurityGroup
IpProtocol: TCP
ToPort: 80
Type: AWS::EC2::SecurityGroupIngress
SimpleLBIngressSecurityGroup80SimpleServiceIngressSecurityGroupIngress:
Properties:
Description: LB connectivity on 80
FromPort: 80
GroupId:
Ref: SimpleServiceIngressSecurityGroup
IpProtocol: TCP
SourceSecurityGroupId:
Ref: SimpleLBIngressSecurityGroup
ToPort: 80
Type: AWS::EC2::SecurityGroupIngress
SimpleService:
DependsOn:
- SimpleTCP80Listener
Expand All @@ -84,6 +106,7 @@ Resources:
AssignPublicIp: ENABLED
SecurityGroups:
- Ref: DefaultNetwork
- Ref: SimpleServiceIngressSecurityGroup
Subnets:
- subnet1
- subnet2
Expand Down Expand Up @@ -117,6 +140,17 @@ Resources:
NamespaceId:
Ref: CloudMap
Type: AWS::ServiceDiscovery::Service
SimpleServiceIngressSecurityGroup:
Properties:
GroupDescription: TestSimpleConvert Security Group for service simple ingress,
Service side
Tags:
- Key: com.docker.compose.project
Value: TestSimpleConvert
- Key: com.docker.compose.service
Value: simple
VpcId: vpc-123
Type: AWS::EC2::SecurityGroup
SimpleTCP80Listener:
Properties:
DefaultActions:
Expand Down
Loading