Skip to content

Deploying fck-nat

The most well-supported way to deploy fck-nat with all of its features available out of the box is via CDK. If you're using another Infrastructure-as-code provider, you can still deploy a basic NAT instance with fck-nat, but it is more intensive to support some of fck-nat's additional features.

CDK

fck-nat provides an official CDK module which supports all of fck-nat's features (namely high-availability mode) out-of-the-box. The CDK module is currently available both in Typescript and Python. You can find detailed documentation on Construct Hub. Here's an example use of the CDK construct in Typescript:

const natGatewayProvider = new FckNatInstanceProvider({
    instanceType: InstanceType.of(InstanceClass.T4G, InstanceSize.NANO),
});
const vpc = new Vpc(this, 'vpc', {
    natGatewayProvider,
});
natGatewayProvider.securityGroup.addIngressRule(Peer.ipv4(vpc.vpcCidrBlock), Port.allTraffic());

That's it! This will deploy your VPC using fck-nat as your NAT provider in high availability mode. This includes all necessary routing configurations and deploys fck-nat in an Autoscaling group to ensure that a new instance is brought up automatically in case the NAT instance is terminated.

You can also deploy fck-nat in non-HA mode using CDK's built-in NatInstanceProvider like so:

const natGatewayProvider = new NatInstanceProviderV2({
    instanceType: InstanceType.of(InstanceClass.T4G, InstanceSize.NANO),
    machineImage: new LookupMachineImage({
        name: 'fck-nat-al2023-*-arm64-ebs',
        owners: ['568608671756'],
    })
})
const vpc = new Vpc(this, 'vpc', {
    natGatewayProvider,
});
natGatewayProvider.securityGroup.addIngressRule(Peer.ipv4(vpc.vpcCidrBlock), Port.allTraffic());

Read more about the NatInstanceProvider construct

Terraform

Doriann Corlouër (RaJiska) maintains the official fck-nat Terraform module over at terraform-aws-fck-nat. Below is a sample of how to use that module and full documentation can be found on the Terraform Registry

module "fck-nat" {
  source = "RaJiska/fck-nat/aws"

  name                 = "my-fck-nat"
  vpc_id               = "vpc-abc1234"
  subnet_id            = "subnet-abc1234"
  # ha_mode              = true                 # Enables high-availability mode
  # eip_allocation_ids   = ["eipalloc-abc1234"] # Allocation ID of an existing EIP
  # use_cloudwatch_agent = true                 # Enables Cloudwatch agent and have metrics reported

  update_route_tables = true
  route_tables_ids = {
    "your-rtb-name-A" = "rtb-abc1234Foo"
    "your-rtb-name-B" = "rtb-abc1234Bar"
  }
}

It is also possible to configure fck-nat with out-of-the-box Terraform modules, but you may not be able to leverage all of fck-nat's features.

data "aws_ami" "fck_nat" {
  filter {
    name   = "name"
    values = ["fck-nat-al2023-*"]
  }

  filter {
    name   = "architecture"
    values = ["arm64"]
  }

  owners      = ["568608671756"]
  most_recent = true
}

resource "aws_network_interface" "fck-nat-if" {
  subnet_id       = aws_subnet.subnet_public.id
  security_groups = [aws_default_security_group.default_security_group.id]

  source_dest_check = false
}

resource "aws_instance" "fck-nat" {                                                   
  ami           = data.aws_ami.fck_nat.id
  instance_type = "t4g.nano"

  network_interface {
    network_interface_id = aws_network_interface.fck-nat-if.id
    device_index         = 0
  }                                                                              
}

CloudFormation

Note

If you'd be interested in seeing fck-nat published on the CloudFormation registry, give this issue a +1

For brevity, this document assumes you already have a VPC with public and private subnets defined in your CloudFormation template. This example template provisions the minimum resources required to connect fck-nat in your VPC. This is a good option for those that have an existing VPC and NAT Gateway and are looking to switch over.

  1. A security group allowing ingress traffic from within the VPC and egress out to the internet
  2. A auto scaling group that creates an EC2 instance using the fck-nat AMI
  3. A route in the private subnet route table directing traffic to the fck-nat instance.

This snippet assumes the following resources are already defined:

  1. VPC: An AWS::EC2::VPC resource.
  2. PublicSubnet: An AWS::EC2::Subnet which has an AWS::EC2::InternetGateway attached.
  3. PrivateSubnetRouteTable: An AWS::EC2::RouteTable with an AWS::EC2::SubnetRouteTableAssociation to a AWS::EC2::Subnet

Steps to deploy:

  1. Paste your VPC ID, public subnet ID, VPC CIDR block into the parameters. Set the FckNatAMIParameter based on the region fck-nat is deployed to.
  2. Deploy with CloudFormation aws cloudformation deploy --force-upload --capabilities CAPABILITY_IAM --template-file template.yml --stack-name FckNat
  3. Add the default route to your route table on the subnet. It is best to do this manually so you can do a seamless cut over from your existing NAT gateway. Go to VPC > Route Tables > Private route table > Routes > Edit Routes Add a 0.0.0.0/0 route pointing to the network interface.
Parameters:
  VpcIdParameter:
    Type: AWS::EC2::VPC::Id
  SubnetIdParameter:
    Type: AWS::EC2::Subnet::Id
  CIDRParameter:
    Type: String
    Default: "10.0.0.0/16"
  FckNatAMIParameter:
    Type: AWS::EC2::Image::Id

Resources:
  FckNatInterface:
    Type: AWS::EC2::NetworkInterface
    Properties:
      Description: FckNat Gateway Interface
      SubnetId: !Ref SubnetIdParameter
      GroupSet:
        - !GetAtt [FckNatSecurityGroup, GroupId]
      SourceDestCheck: false
  FckNatAsgInstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      Roles:
        - !Ref FckNatRole
  FckNatLaunchTemplate:
    Type: AWS::EC2::LaunchTemplate
    DependsOn: FckNatRole
    Properties:
      LaunchTemplateName: FckNatLaunchTemplate
      LaunchTemplateData:
        ImageId: !Ref FckNatAMIParameter
        InstanceType: t4g.nano
        NetworkInterfaces:
          - DeviceIndex: 0
            AssociatePublicIpAddress: true
            Groups:
            - !GetAtt [FckNatSecurityGroup, GroupId]
        IamInstanceProfile:
          Name: !Ref FckNatAsgInstanceProfile
        UserData:
          Fn::Base64: !Sub |
            #!/bin/bash
            echo "eni_id=${FckNatInterface}" >> /etc/fck-nat.conf
            service fck-nat restart
  FckNatAsg:
    Type: AWS::AutoScaling::AutoScalingGroup
    Properties:
      MaxSize: "1"
      MinSize: "1"
      DesiredCapacity: "1"
      LaunchTemplate:
        LaunchTemplateId: !Ref FckNatLaunchTemplate
        Version: !GetAtt FckNatLaunchTemplate.LatestVersionNumber
      VPCZoneIdentifier:
        - !Ref SubnetIdParameter
      Tags:
        - Key: Name
          Value: fck-nat
          PropagateAtLaunch: true
    UpdatePolicy:
      AutoScalingScheduledAction:
        IgnoreUnmodifiedGroupSizeProperties: true
  FckNatSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Security Group for FckNat
      SecurityGroupIngress:
        - CidrIp: !Ref CIDRParameter
          IpProtocol: "-1"
      SecurityGroupEgress:
        - CidrIp: 0.0.0.0/0
          Description: Allow all outbound traffic by default
          IpProtocol: "-1"
      VpcId: !Ref VpcIdParameter
  FckNatRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Action: sts:AssumeRole
            Effect: Allow
            Principal:
              Service: ec2.amazonaws.com
        Version: "2012-10-17"
      Policies:
        - PolicyName: AttachNatEniPolicy
          PolicyDocument:
            Statement:
              - Action:
                  - ec2:AttachNetworkInterface
                  - ec2:ModifyNetworkInterfaceAttribute
                Effect: Allow
                Resource: "*"
            Version: "2012-10-17"
        - PolicyName: AssociateNatAddressPolicy
          PolicyDocument:
            Statement:
              - Action:
                  - ec2:AssociateAddress
                  - ec2:DisassociateAddress
                Effect: Allow
                Resource: "*"
            Version: "2012-10-17"

Manual - Web Console

The following instructions can be used to deploy the fck-nat AMI manually.
**Summary: ** 1. Launch fck-nat AMI 2. Modify ENI to disable source/dest check 3. Modify the private route table, default route to fck-nat target 4. Validate

NOTE: The following example uses fck-nat AMI version 1.2.0 for arm64 on t4g.nano.

EC2 Instance Launch

  1. Visit the EC2 service in your preferred region: EC2 Link
  2. Click Launch Instances
    Launch Instance
  3. Give the instance a name
    Name Instance
  4. Search for AMIs owned by "568608671756" Search AMI
  5. Select the ARM64 1.2.0 fck-nat AMI
    Select AMI
    AMI Selected
  6. Select Instance Type t4g.nano
    Select t4g.nano
  7. Modify Network Settings
  8. Select VPC
  9. Place in public subnet, ensure Public IP is assigned
  10. Attached Security group that permits
    inbound: entire VPC CIDR inbound, all traffic
    outbound: 0.0.0.0/0, all traffic
    Network Settings
  11. Leave Storage at 2GB
    Storage Settings
  12. Review and launch
    Review and Launch

Wait for Launch

Modify EC2 Network Interface

We must modify the ENI attached to the newly launched instance to disable source/destination checks, this allows us to route through (actually hairpinning) the instance. 1. Click on the ENI of the instance
Modify ENI
2. Select ENI, Click Actions -> Change source/dest. check
change source dest check
3. Disable Source/Dest check and Save
change source dest check

Modify VPC Routing Table

The VPC routing table associated with your private subnets must be modified to route traffic matching the default route to the new fck-nat instance.
1. Open the VPC Service, Route Tables
Route Tables
2. Open the private route table, edit routes
Edit private route table
3. Add a default route, target: fck-nat instance
Add default route

Validate

Log into an instance in a private subnet and validate the external IP is the public IP assigned to your fck-nat instance.

Validate