ECS Fargate tasks- How to avoid assignment of public IPv4?

0

This is my network definition

Resources:

  InternetGateway:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: Name
          Value: !Sub "${AWS::StackName}-Internet-Gateway"

  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.1.0.0/16
      EnableDnsSupport: "true"
      EnableDnsHostnames: "true"
      Tags:
        - Key: Name
          Value: !Sub "${AWS::StackName}-VPC"
  
  InternetGatewayAttachment:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      InternetGatewayId: !Ref InternetGateway
      VpcId: !Ref VPC

  VPCIpv6CidrBlock:
    Type: AWS::EC2::VPCCidrBlock
    Properties:
      VpcId: !Ref VPC
      AmazonProvidedIpv6CidrBlock: true

  PublicIpv6SubnetA:
    Type: AWS::EC2::Subnet
    DependsOn: VPCIpv6CidrBlock
    Properties:
      CidrBlock: !Select [0, !Cidr [!GetAtt VPC.CidrBlock, 256, 8]]
      AssignIpv6AddressOnCreation: true
      Ipv6CidrBlock: !Select [0, !Cidr [!Select [0, !GetAtt VPC.Ipv6CidrBlocks], 256, 64]]
      AvailabilityZone: !Select [0, !GetAZs ""]
      VpcId: !Ref VPC
      EnableDns64: true
      Tags:
        - Key: Name
          Value: !Sub "${AWS::StackName}-IPV6-Subnet-A"

  PublicIpv6SubnetB:
    Type: AWS::EC2::Subnet
    DependsOn: VPCIpv6CidrBlock
    Properties:
      CidrBlock: !Select [1, !Cidr [!GetAtt VPC.CidrBlock, 256, 8]]
      AssignIpv6AddressOnCreation: true
      Ipv6CidrBlock: !Select [1, !Cidr [!Select [0, !GetAtt VPC.Ipv6CidrBlocks], 256, 64]]
      AvailabilityZone: !Select [1, !GetAZs ""]
      VpcId: !Ref VPC
      EnableDns64: true
      Tags:
        - Key: Name
          Value: !Sub "${AWS::StackName}-IPV6-Subnet-B"

  PublicIpv6SubnetC:
    Type: AWS::EC2::Subnet
    DependsOn: VPCIpv6CidrBlock
    Properties:
      CidrBlock: !Select [2, !Cidr [!GetAtt VPC.CidrBlock, 256, 8]]
      AssignIpv6AddressOnCreation: true
      Ipv6CidrBlock: !Select [2, !Cidr [!Select [0, !GetAtt VPC.Ipv6CidrBlocks], 256, 64]]
      AvailabilityZone: !Select [2, !GetAZs ""]
      VpcId: !Ref VPC
      EnableDns64: true
      Tags:
        - Key: Name
          Value: !Sub "${AWS::StackName}-IPV6-Subnet-C"

  PublicRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Sub "${AWS::StackName}-Public-Route-Table"

  PublicIpv6SubnetAPublicRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref PublicRouteTable
      SubnetId: !Ref PublicIpv6SubnetA

  PublicIpv6SubnetBPublicRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref PublicRouteTable
      SubnetId: !Ref PublicIpv6SubnetB

  PublicIpv6SubnetCPublicRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref PublicRouteTable
      SubnetId: !Ref PublicIpv6SubnetC

  RouteForOutboundIpv4:
    Type: AWS::EC2::Route
    DependsOn: InternetGatewayAttachment
    Properties:
      RouteTableId: !Ref PublicRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref InternetGateway

  RouteForOutboundIpv6:
    Type: AWS::EC2::Route
    DependsOn: InternetGatewayAttachment
    Properties:
      RouteTableId: !Ref PublicRouteTable
      DestinationIpv6CidrBlock: ::/0
      GatewayId: !Ref InternetGateway

  PublicNetworkAcl:
    Type: AWS::EC2::NetworkAcl
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Sub "${AWS::StackName}-Public-NACL"

  PublicNACLAssociationToPublicIpv6SubnetA:
    Type: AWS::EC2::SubnetNetworkAclAssociation
    Properties:
      NetworkAclId: !Ref PublicNetworkAcl
      SubnetId: !Ref PublicIpv6SubnetA

  PublicNACLAssociationToPublicIpv6SubnetB:
    Type: AWS::EC2::SubnetNetworkAclAssociation
    Properties:
      NetworkAclId: !Ref PublicNetworkAcl
      SubnetId: !Ref PublicIpv6SubnetB

  PublicNACLAssociationToPublicIpv6SubnetC:
    Type: AWS::EC2::SubnetNetworkAclAssociation
    Properties:
      NetworkAclId: !Ref PublicNetworkAcl
      SubnetId: !Ref PublicIpv6SubnetC

  NACLAllowInboundIpv4:
    Type: AWS::EC2::NetworkAclEntry
    Properties:
      NetworkAclId: !Ref PublicNetworkAcl
      CidrBlock: 0.0.0.0/0
      RuleNumber: 100
      Protocol: -1
      RuleAction: allow
      Egress: false

  NACLAllowInboundIpv6:
    Type: AWS::EC2::NetworkAclEntry
    Properties:
      NetworkAclId: !Ref PublicNetworkAcl
      Ipv6CidrBlock: ::/0
      RuleNumber: 101
      Protocol: -1
      RuleAction: allow
      Egress: false

  NACLAllowOutboundIpv4:
    Type: AWS::EC2::NetworkAclEntry
    Properties:
      NetworkAclId: !Ref PublicNetworkAcl
      CidrBlock: 0.0.0.0/0
      RuleNumber: 100
      Protocol: -1
      RuleAction: allow
      Egress: true

  NACLAllowOutboundIpv6:
    Type: AWS::EC2::NetworkAclEntry
    Properties:
      NetworkAclId: !Ref PublicNetworkAcl
      Ipv6CidrBlock: ::/0
      RuleNumber: 101
      Protocol: -1
      RuleAction: allow
      Egress: true

Outputs:
  VPCId:
    Value: !Ref VPC
    Export:
      Name: Network-V1-VPC
  SubnetAId:
    Value: !Ref PublicIpv6SubnetA
    Export:
      Name: Network-V1-SubnetA
  SubnetBId:
    Value: !Ref PublicIpv6SubnetB
    Export:
      Name: Network-V1-SubnetB
  SubnetCId:
    Value: !Ref PublicIpv6SubnetC
    Export:
      Name: Network-V1-SubnetC
  

and this is my ECS Service definition

Parameters:
  LatestAmiId:
    Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
    Default: /aws/service/ami-amazon-linux-latest/al2023-ami-minimal-kernel-default-x86_64

Resources:

  WebServerSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      VpcId: !ImportValue 'Network-V1-VPC'
      GroupDescription: !Sub "${AWS::StackName}-Webserver-Security-Group"
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIpv6: ::/0
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: 0.0.0.0/0      
      Tags:
        - Key: Name
          Value: !Sub "${AWS::StackName}-Webserver-Security-Group"

  LoadBalancerSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: !Sub "${AWS::StackName}-Load-Balancer-Security-Group"
      VpcId: !ImportValue 'Network-V1-VPC'
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 443
          ToPort: 443
          CidrIp: 0.0.0.0/0
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: 0.0.0.0/0
        - IpProtocol: tcp
          FromPort: 443
          ToPort: 443
          CidrIpv6: 0::/0
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIpv6: 0::/0

  LoadBalancer:
    Type: AWS::ElasticLoadBalancingV2::LoadBalancer
    Properties:
      Name: !Sub "${AWS::StackName}-Load-Balancer"
      Scheme: internet-facing
      IpAddressType: dualstack-without-public-ipv4
      Subnets:
        - !ImportValue Network-V1-SubnetA
        - !ImportValue Network-V1-SubnetB
        - !ImportValue Network-V1-SubnetC
      SecurityGroups:
        - !Ref LoadBalancerSecurityGroup
      LoadBalancerAttributes:
        - Key: idle_timeout.timeout_seconds
          Value: 60
      Tags:
        - Key: Name
          Value: !Sub "${AWS::StackName}-Load-Balancer"

  TargetGroup:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
      Name: !Sub "${AWS::StackName}-Target-Group"
      Port: 80  # La porta su cui il target group ascolta il traffico
      Protocol: HTTP  # Il protocollo utilizzato dal target group (HTTP, HTTPS, TCP, etc.)
      VpcId: !ImportValue 'Network-V1-VPC' # ID della VPC in cui verrà creato il target group
      TargetType: ip
      HealthCheckEnabled: true  # Abilita i controlli di integrità
      HealthCheckProtocol: HTTP  # Protocollo utilizzato per i controlli di integrità
      HealthCheckPort: 80  # Porta su cui eseguire i controlli di integrità
      HealthCheckPath: /  # Percorso per i controlli di integrità
      Matcher:  # Configurazione del criterio di corrispondenza dei controlli di integrità
        HttpCode: 200
      TargetGroupAttributes:  # Attributi aggiuntivi del target group (opzionale)
        - Key: deregistration_delay.timeout_seconds
          Value: "30"  # Timeout in secondi prima che una destinazione viene considerata non disponibile dopo una deregistrazione
      Tags:  # Tags per identificare e organizzare il target group (opzionale)
        - Key: Name
          Value: !Sub "${AWS::StackName}-Target-Group"
  
  ListenerHTTP:
    Type: AWS::ElasticLoadBalancingV2::Listener
    Properties:
      DefaultActions:
        - TargetGroupArn: !Ref TargetGroup
          Type: forward
      LoadBalancerArn: !Ref LoadBalancer
      Port: 80
      Protocol: HTTP

  AutoScalingRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub "${AWS::StackName}-Autoscaling-Role"
      AssumeRolePolicyDocument:
        Statement:
          Effect: Allow
          Principal:
            Service: ecs-tasks.amazonaws.com
          Action: sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceAutoscaleRole

  ECSCluster:
    Type: AWS::ECS::Cluster
    Properties:
      ClusterName: !Sub "${AWS::StackName}-ECS-Cluster"
      CapacityProviders:
        - FARGATE
        - FARGATE_SPOT
      DefaultCapacityProviderStrategy:
        - CapacityProvider: FARGATE
          Weight: 1
        - CapacityProvider: FARGATE_SPOT
          Weight: 3
          Base: 1

  MainTaskDefinition:
    Type: AWS::ECS::TaskDefinition
    Properties:
      Family: !Sub "${AWS::StackName}-Main-Task-Definition"
      RequiresCompatibilities:
        - FARGATE
      Cpu: 1024
      Memory: 2048
      NetworkMode: awsvpc
      ContainerDefinitions:
        - Name: !Sub "${AWS::StackName}-Container-Definition"
          Image: amazon/amazon-ecs-sample
          Cpu: 1024
          Memory: 2048
          PortMappings:
            - ContainerPort: 80
              Protocol: tcp

  ClusterService:
    Type: AWS::ECS::Service
    DependsOn:
      - ListenerHTTP
    Properties:
      ServiceName: !Sub "${AWS::StackName}-Cluster-Service"
      Cluster: !Ref ECSCluster
      TaskDefinition:
        Ref: MainTaskDefinition
      DeploymentConfiguration:
        MinimumHealthyPercent: 100
        MaximumPercent: 200
      DeploymentController:
        Type: ECS
      SchedulingStrategy: REPLICA
      DesiredCount: 1
      HealthCheckGracePeriodSeconds: 10
      NetworkConfiguration:
        AwsvpcConfiguration:
          AssignPublicIp: ENABLED
          Subnets:
            - !ImportValue Network-V1-SubnetA
            - !ImportValue Network-V1-SubnetB
            - !ImportValue Network-V1-SubnetC
          SecurityGroups:
            - Ref: WebServerSecurityGroup
      LoadBalancers:
        - ContainerName: !Sub "${AWS::StackName}-Container-Definition"
          ContainerPort: 80
          TargetGroupArn:
            Ref: TargetGroup
      CapacityProviderStrategy:
        - CapacityProvider: FARGATE
          Weight: 1
        - CapacityProvider: FARGATE_SPOT
          Weight: 3
          Base: 1

# Outputs:
#   VPCIpv6Cidr:
#     Description: IPv6 CIDR Blocks for the VPC
#     Value: !Join [ ", ", !GetAtt VPC.Ipv6CidrBlocks ]

My problem is that FARGATE instances are receing a public ipv4 address Why? This is a bad practice, and. I don't need an ipv4 for each instance, because I placed them behind a load balancer Also, the ALB is defined as IpAddressType: dualstack-without-public-ipv4

What am I missing? How to avoid to receive a public (and billed) ipv4 address for each Fairgate instances ?

2 Answers
3
Accepted Answer

Found !

NetworkConfiguration:
        AwsvpcConfiguration:
          AssignPublicIp: ENABLED

I missed to change to DISABLED

answered 24 days ago
profile picture
EXPERT
reviewed 24 days ago
profile picture
EXPERT
A_J
reviewed 24 days ago
profile pictureAWS
EXPERT
reviewed 24 days ago
0

Hiii,

This explanation gives you the answer about your issue.

The issue lies in your ECS Service definition specifically within the Network Configuration section. You've correctly configured the Load Balancer (Ip Address Type: dualstack-without-public-ipv4) to not assign a public IPv4 address, but the ECS Service itself is still requesting one.

Modify AssignPublicIp in NetworkConfiguration:

Change the value of AssignPublicIp to DISABLED within the AwsvpcConfiguration block of your NetworkConfiguration section. This explicitly tells ECS not to assign a public IPv4 address to the Fargate tasks.

NetworkConfiguration:

AwsvpcConfiguration:

AssignPublicIp: DISABLED  # Set to DISABLED

Subnets:

  - !ImportValue Network-V1-SubnetA

  - !ImportValue Network-V1-SubnetB

  - !ImportValue Network-V1-SubnetC

SecurityGroups:

  - Ref: WebServerSecurityGroup

Redeploy your ECS Service:

After making the change, redeploy your ECS Service to ensure the new configuration takes effect.

answered 24 days ago
profile picture
EXPERT
A_J
reviewed 24 days ago

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.

Guidelines for Answering Questions