Skip to content

Commit c0054f1

Browse files
Merge branch 'main' into BREV-6888/nebius-provisioning-fail
2 parents 4ff1d4d + 4fb53cc commit c0054f1

1 file changed

Lines changed: 25 additions & 1 deletion

File tree

v1/providers/nebius/instance.go

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1752,6 +1752,7 @@ func generateCloudInitUserData(publicKey string, firewallRules v1.FirewallRules)
17521752
script := `#cloud-config
17531753
packages:
17541754
- ufw
1755+
- iptables-persistent
17551756
`
17561757

17571758
// Add SSH key configuration if provided
@@ -1762,6 +1763,19 @@ packages:
17621763
}
17631764

17641765
var commands []string
1766+
1767+
// Fix a systemd race condition: ufw.service and netfilter-persistent.service
1768+
// both start in parallel (both are Before=network-pre.target with no mutual
1769+
// ordering). Both call iptables-restore concurrently, and with the iptables-nft
1770+
// backend the competing nftables transactions cause UFW to fail with
1771+
// "iptables-restore: line 4 failed". This drop-in forces UFW to wait for
1772+
// netfilter-persistent to finish first.
1773+
commands = append(commands,
1774+
"sudo mkdir -p /etc/systemd/system/ufw.service.d",
1775+
`printf '[Unit]\nAfter=netfilter-persistent.service\n' | sudo tee /etc/systemd/system/ufw.service.d/after-netfilter.conf > /dev/null`,
1776+
"sudo systemctl daemon-reload",
1777+
)
1778+
17651779
// Generate UFW firewall commands (similar to Shadeform's approach)
17661780
// UFW (Uncomplicated Firewall) is available on Ubuntu/Debian instances
17671781
commands = append(commands, generateUFWCommands(firewallRules)...)
@@ -1770,11 +1784,21 @@ packages:
17701784
// accessible from the internet by default.
17711785
commands = append(commands, generateIPTablesCommands()...)
17721786

1787+
// Save the complete iptables state (UFW chains + DOCKER-USER rules) so it
1788+
// survives instance stop/start cycles. Cloud-init runcmd only executes on
1789+
// first boot; on subsequent boots netfilter-persistent restores this snapshot,
1790+
// then UFW starts after it (due to the drop-in above) and re-applies its rules.
1791+
// This provides defense-in-depth: even if UFW fails for any reason, the
1792+
// netfilter-persistent snapshot ensures port 22 and DOCKER-USER rules persist.
1793+
commands = append(commands, "sudo netfilter-persistent save")
1794+
17731795
if len(commands) > 0 {
17741796
// Use runcmd to execute firewall setup commands
17751797
script += "\nruncmd:\n"
17761798
for _, cmd := range commands {
1777-
script += fmt.Sprintf(" - %s\n", cmd)
1799+
escaped := strings.ReplaceAll(cmd, `\`, `\\`)
1800+
escaped = strings.ReplaceAll(escaped, `"`, `\"`)
1801+
script += fmt.Sprintf(" - \"%s\"\n", escaped)
17781802
}
17791803
}
17801804

0 commit comments

Comments
 (0)