Skip to content

Commit 0c41aa8

Browse files
authored
fix: support Amazon Linux 2023 for NAT instance (#81)
## Summary CDK's `NatInstanceProviderV2` uses the `route` command in its default user data, which requires the `net-tools` package. However, Amazon Linux 2023 (the default AMI for `NatInstanceProviderV2`) doesn't have `net-tools` pre-installed, causing NAT instances to fail silently. ## Problem The default user data in CDK contains: ```bash sudo /sbin/iptables -t nat -A POSTROUTING -o $(route | awk '/^default/{print $NF}') -j MASQUERADE ``` This fails on AL2023 because the `route` command is not available. ## Solution This change provides custom user data that uses `ip route` instead of `route` to determine the default network interface: ```bash IFACE=$(ip route show default | awk '{print $5}') /sbin/iptables -t nat -A POSTROUTING -o $IFACE -j MASQUERADE ``` ## Reference - CDK source code: https://github.com/aws/aws-cdk/blob/main/packages/aws-cdk-lib/aws-ec2/lib/nat.ts ## Testing - Deployed the stack with the fix and verified NAT instance works correctly - Application accessible via CloudFront (returns 307 redirect to sign-in page as expected)
1 parent f00fa21 commit 0c41aa8

File tree

3 files changed

+32
-11
lines changed

3 files changed

+32
-11
lines changed

cdk/lib/main-stack.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { Construct } from 'constructs';
44
import { AsyncJob } from './constructs/async-job';
55
import { Auth } from './constructs/auth/';
66
import { Database } from './constructs/database';
7-
import { InstanceClass, InstanceSize, InstanceType, NatProvider, Vpc } from 'aws-cdk-lib/aws-ec2';
7+
import { InstanceClass, InstanceSize, InstanceType, NatProvider, UserData, Vpc } from 'aws-cdk-lib/aws-ec2';
88
import { HostedZone } from 'aws-cdk-lib/aws-route53';
99
import { ICertificate } from 'aws-cdk-lib/aws-certificatemanager';
1010
import { Webapp } from './constructs/webapp';
@@ -56,12 +56,31 @@ export class MainStack extends Stack {
5656
autoDeleteObjects: true,
5757
});
5858

59+
// Custom user data for NAT instance to support Amazon Linux 2023.
60+
// CDK's default user data uses `route` command which requires net-tools package,
61+
// but AL2023 doesn't have net-tools pre-installed. We use `ip route` instead.
62+
// Retry yum install to handle RPM lock conflicts during boot.
63+
const natUserData = UserData.forLinux();
64+
natUserData.addCommands(
65+
// Retry yum install up to 5 times with 10 second intervals
66+
'for i in {1..5}; do yum install iptables-services -y && break || sleep 10; done',
67+
'systemctl enable iptables',
68+
'systemctl start iptables',
69+
'echo "net.ipv4.ip_forward=1" > /etc/sysctl.d/custom-ip-forwarding.conf',
70+
'sysctl -p /etc/sysctl.d/custom-ip-forwarding.conf',
71+
"IFACE=$(ip route show default | awk '{print $5}')",
72+
'/sbin/iptables -t nat -A POSTROUTING -o $IFACE -j MASQUERADE',
73+
'/sbin/iptables -F FORWARD',
74+
'service iptables save',
75+
);
76+
5977
const vpc = new Vpc(this, `Vpc`, {
6078
...(useNatInstance
6179
? {
6280
natGatewayProvider: NatProvider.instanceV2({
6381
instanceType: InstanceType.of(InstanceClass.T4G, InstanceSize.NANO),
6482
associatePublicIpAddress: true,
83+
userData: natUserData,
6584
}),
6685
natGateways: 1,
6786
}

cdk/test/__snapshots__/serverless-fullstack-webapp-starter-kit-without-domain.test.ts.snap

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2712,14 +2712,15 @@ exports.handler = async function (event, context) {
27122712
],
27132713
"UserData": {
27142714
"Fn::Base64": "#!/bin/bash
2715-
yum install iptables-services -y
2715+
for i in {1..5}; do yum install iptables-services -y && break || sleep 10; done
27162716
systemctl enable iptables
27172717
systemctl start iptables
27182718
echo "net.ipv4.ip_forward=1" > /etc/sysctl.d/custom-ip-forwarding.conf
2719-
sudo sysctl -p /etc/sysctl.d/custom-ip-forwarding.conf
2720-
sudo /sbin/iptables -t nat -A POSTROUTING -o $(route | awk '/^default/{print $NF}') -j MASQUERADE
2721-
sudo /sbin/iptables -F FORWARD
2722-
sudo service iptables save",
2719+
sysctl -p /etc/sysctl.d/custom-ip-forwarding.conf
2720+
IFACE=$(ip route show default | awk '{print $5}')
2721+
/sbin/iptables -t nat -A POSTROUTING -o $IFACE -j MASQUERADE
2722+
/sbin/iptables -F FORWARD
2723+
service iptables save",
27232724
},
27242725
},
27252726
"Type": "AWS::EC2::Instance",

cdk/test/__snapshots__/serverless-fullstack-webapp-starter-kit.test.ts.snap

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2544,14 +2544,15 @@ exports[`Snapshot test 2`] = `
25442544
],
25452545
"UserData": {
25462546
"Fn::Base64": "#!/bin/bash
2547-
yum install iptables-services -y
2547+
for i in {1..5}; do yum install iptables-services -y && break || sleep 10; done
25482548
systemctl enable iptables
25492549
systemctl start iptables
25502550
echo "net.ipv4.ip_forward=1" > /etc/sysctl.d/custom-ip-forwarding.conf
2551-
sudo sysctl -p /etc/sysctl.d/custom-ip-forwarding.conf
2552-
sudo /sbin/iptables -t nat -A POSTROUTING -o $(route | awk '/^default/{print $NF}') -j MASQUERADE
2553-
sudo /sbin/iptables -F FORWARD
2554-
sudo service iptables save",
2551+
sysctl -p /etc/sysctl.d/custom-ip-forwarding.conf
2552+
IFACE=$(ip route show default | awk '{print $5}')
2553+
/sbin/iptables -t nat -A POSTROUTING -o $IFACE -j MASQUERADE
2554+
/sbin/iptables -F FORWARD
2555+
service iptables save",
25552556
},
25562557
},
25572558
"Type": "AWS::EC2::Instance",

0 commit comments

Comments
 (0)