Bug in StackScript Bash Library configure_basic_firewall on Ubuntu 23.10

Not sure if this is the place to report this but there seems to be a bug in the StackScript Bash Library

I have the following StackScript

#!/bin/bash

# <UDF name="admin_password" label="The default user password">
# <UDF name="admin_username" label="The default user name">
# <UDF name="admin_pubkey" label="The default user account's public key">
# <UDF name="hostname" label="The hostname for the new instance">

source <ssinclude StackScriptID="1">

get_started "" "$HOSTNAME" $(system_primary_ip)

system_update

secure_server "$ADMIN_USERNAME" "$ADMIN_PASSWORD" "$ADMIN_PUBKEY"

I spin up a new Linode using Ubuntu 23.10 but after it finishes I can't connect.

If I use LISH to get in and run iptables --list I see that port 22 hasn't been allowed

Chain INPUT (policy DROP)
target     prot opt source               destination
ACCEPT     all  --  anywhere             anywhere             state RELATED,ESTABLISHED
ACCEPT     all  --  anywhere             anywhere             /* Allow loopback connections */
ACCEPT     icmp --  anywhere             anywhere             /* Allow Ping to work as expected */

Chain FORWARD (policy DROP)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

But the secure_server function calls configure_basic_firewall which calls

add_port 'ipv4' 22 'tcp'
add_port 'ipv6' 22 'tcp'
save_firewall

So it looks like it should work

If I change my StackScript to add these 3 lines, or the following, after secure_server and spin up a new instance I can get in

add_ports 22
save_firewall

So I changed the StackScript to exit immediately and add set -x to the beginning then spin up a new instance.

When it was up I got into the instance and removed the exit from the script and then ran it (setting appropriate ENV variables)

root@localhost:~# ./StackScript
++ system_primary_ip
+++ awk '/inet / {print $2}'
+++ ip a
++ local 'ip_address=127.0.0.1/8
88.80.184.76/24'
++ cut -d/ -f 1
++ cut '-d ' -f 2
++ echo 127.0.0.1/8 88.80.184.76/24
+ get_started '' rebelinblue.com 88.80.184.76
+ local -r subdomain= domain=rebelinblue.com ip=88.80.184.76
+ '[' rebelinblue.com ']'
+ '[' '' ']'
+ local -r fqdn=rebelinblue.com
+ local -r hostname=rebelinblue.com
+ printf 'Setting IP Address (%s), fqdn (%s), and hostname (%s) in /etc/hosts...\n' 88.80.184.76 rebelinblue.com rebelinblue.com
Setting IP Address (88.80.184.76), fqdn (rebelinblue.com), and hostname (rebelinblue.com) in /etc/hosts...
+ system_add_host_entry 88.80.184.76 rebelinblue.com rebelinblue.com
+ local -r ip_address=88.80.184.76 fqdn=rebelinblue.com hostname=rebelinblue.com
+ '[' -z 88.80.184.76 -o -z rebelinblue.com ']'
+ echo '88.80.184.76 rebelinblue.com rebelinblue.com'
+ system_update
+ case "${detected_distro[family]}" in
+ echo 'Acquire::ForceIPv4 "true";'
+ printf 'Checking for initial updates...\n'
Checking for initial updates...
+ DEBIAN_FRONTEND=noninteractive
+ apt-get update -qq
+ system_set_hostname rebelinblue.com
+ local -r hostname=rebelinblue.com
+ '[' '!' -n rebelinblue.com ']'
+ hostnamectl set-hostname rebelinblue.com
+ system_update
+ case "${detected_distro[family]}" in
+ echo 'Acquire::ForceIPv4 "true";'
+ printf 'Checking for initial updates...\n'
Checking for initial updates...
+ DEBIAN_FRONTEND=noninteractive
+ apt-get update -qq
+ secure_server stephen blahblahblbha 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEgnlCD5hNitroeqHKun4svSkQwkt6OcWkTyA0g66Wj5'
+ '[' '!' -n stephen ']'
+ '[' '!' -n blahblahblbha ']'
+ '[' '!' -n 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEgnlCD5hNitroeqHKun4svSkQwkt6OcWkTyA0g66Wj5' ']'
+ local -r user=stephen password=blahblahblbha 'pubkey=ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEgnlCD5hNitroeqHKun4svSkQwkt6OcWkTyA0g66Wj5'
+ user_add_sudo stephen blahblahblbha
+ '[' '!' -n stephen -o '!' -n blahblahblbha ']'
+ local -r username=stephen userpass=blahblahblbha
+ '[' '!' -x /usr/bin/sudo ']'
+ case "${detected_distro[family]}" in
+ adduser stephen --disabled-password --gecos ''
info: Adding user `stephen' ...
info: Selecting UID/GID from range 1000 to 59999 ...
info: Adding new group `stephen' (1000) ...
info: Adding new user `stephen' (1000) with group `stephen (1000)' ...
info: Creating home directory `/home/stephen' ...
info: Copying files from `/etc/skel' ...
info: Adding new user `stephen' to supplemental / extra groups `users' ...
info: Adding user `stephen' to group `users' ...
+ chpasswd
+ echo stephen:blahblahblbha
+ adduser stephen sudo
+ user_add_pubkey stephen 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEgnlCD5hNitroeqHKun4svSkQwkt6OcWkTyA0g66Wj5'
+ '[' '!' -n stephen -o '!' -n 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEgnlCD5hNitroeqHKun4svSkQwkt6OcWkTyA0g66Wj5' ']'
+ local -r username=stephen 'userpubkey=ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEgnlCD5hNitroeqHKun4svSkQwkt6OcWkTyA0g66Wj5'
+ case "$username" in
+ mkdir -p /home/stephen/.ssh
+ chmod -R 700 /home/stephen/.ssh/
+ echo 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEgnlCD5hNitroeqHKun4svSkQwkt6OcWkTyA0g66Wj5'
+ chown -R stephen:stephen /home/stephen/.ssh
+ chmod 600 /home/stephen/.ssh/authorized_keys
+ ssh_disable_root
+ sed -i 's/PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config
+ sed -i -e 's/#PermitRootLogin no/PermitRootLogin no/' /etc/ssh/sshd_config
+ sed -i -e 's/PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
+ sed -i -e 's/#PasswordAuthentication no/PasswordAuthentication no/' /etc/ssh/sshd_config
+ '[' debian == debian ']'
+ systemctl restart ssh
+ '[' debian == redhat ']'
+ configure_basic_firewall
+ case "${detected_distro[family]}" in
+ iptables --policy INPUT DROP
+ iptables --policy OUTPUT ACCEPT
+ iptables --policy FORWARD DROP
+ iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
+ iptables -A INPUT -i lo -m comment --comment 'Allow loopback connections' -j ACCEPT
+ iptables -A INPUT -p icmp -m comment --comment 'Allow Ping to work as expected' -j ACCEPT
+ ip6tables --policy INPUT DROP
+ ip6tables --policy OUTPUT ACCEPT
+ ip6tables --policy FORWARD DROP
+ ip6tables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
+ ip6tables -A INPUT -i lo -m comment --comment 'Allow loopback connections' -j ACCEPT
+ ip6tables -A INPUT -p icmpv6 -m comment --comment 'Allow Ping to work as expected' -j ACCEPT
+ add_port ipv4 22 tcp
+ '[' '!' -n ipv4 ']'
+ '[' '!' -n 22 ']'
+ '[' '!' -n tcp ']'
+ local -r standard=ipv4 port=22 protocol=tcp
+ case "${detected_distro[family]}" in
+ '[' -x /usr/sbin/ufw ']'
+ ufw allow 22/tcp
Rules updated
Rules updated (v6)
+ add_port ipv6 22 tcp
+ '[' '!' -n ipv6 ']'
+ '[' '!' -n 22 ']'
+ '[' '!' -n tcp ']'
+ local -r standard=ipv6 port=22 protocol=tcp
+ case "${detected_distro[family]}" in
+ '[' -x /usr/sbin/ufw ']'
+ ufw allow 22/tcp
Skipping adding existing rule
Skipping adding existing rule (v6)
+ save_firewall
+ case "${detected_distro[family]}" in
+ printf 'Saving firewall rules for IPv4 and IPv6...\n'
Saving firewall rules for IPv4 and IPv6...
+ sudo debconf-set-selections
+ echo iptables-persistent iptables-persistent/autosave_v4 boolean true
+ sudo debconf-set-selections
+ echo iptables-persistent iptables-persistent/autosave_v6 boolean true
+ system_install_package iptables-persistent
+ '[' '!' -n iptables-persistent ']'
+ packages=('iptables-persistent')
+ local packages
+ case "${detected_distro['family']}" in
+ DEBIAN_FRONTEND=noninteractive
+ apt-get -y install iptables-persistent -qq
Scanning processes...
Scanning linux images...
+ enable_fail2ban
+ system_install_package fail2ban
+ '[' '!' -n fail2ban ']'
+ packages=('fail2ban')
+ local packages
+ case "${detected_distro['family']}" in
+ DEBIAN_FRONTEND=noninteractive
+ apt-get -y install fail2ban -qq
Scanning processes...
Scanning linux images...
+ cd /etc/fail2ban
+ cp fail2ban.conf fail2ban.local
+ cp jail.conf jail.local
+ sed -i -e 's/backend = auto/backend = systemd/' /etc/fail2ban/jail.local
+ systemctl enable fail2ban
Synchronizing state of fail2ban.service with SysV service script with /lib/systemd/systemd-sysv-install.
Executing: /lib/systemd/systemd-sysv-install enable fail2ban
+ systemctl start fail2ban
+ cd /root/
+ systemctl start fail2ban
+ systemctl enable fail2ban
Synchronizing state of fail2ban.service with SysV service script with /lib/systemd/systemd-sysv-install.
Executing: /lib/systemd/systemd-sysv-install enable fail2ban

I can sort of see the problem

+ '[' -x /usr/sbin/ufw ']'
+ ufw allow 22/tcp
Skipping adding existing rule
Skipping adding existing rule (v6)
+ save_firewall

So /usr/sbin/ufw seems to be being found so it is creating firewall rules using ufw, but then if you call add_ports it uses iptables instead

+ add_ports 22
+ ports=('22')
+ local -a ports
+ for i in "${ports[@]}"
+ add_port ipv4 22 tcp
+ '[' '!' -n ipv4 ']'
+ '[' '!' -n 22 ']'
+ '[' '!' -n tcp ']'
+ local -r standard=ipv4 port=22 protocol=tcp
+ case "${detected_distro[family]}" in
+ '[' -x /usr/sbin/ufw ']'
+ case "$standard" in
+ iptables -A INPUT -p tcp --dport 22 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
+ add_port ipv6 22 tcp
+ '[' '!' -n ipv6 ']'
+ '[' '!' -n 22 ']'
+ '[' '!' -n tcp ']'
+ local -r standard=ipv6 port=22 protocol=tcp
+ case "${detected_distro[family]}" in
+ '[' -x /usr/sbin/ufw ']'
+ case "$standard" in
+ ip6tables -A INPUT -p tcp --dport 22 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
+ save_firewall
+ case "${detected_distro[family]}" in
+ printf 'Saving firewall rules for IPv4 and IPv6...\n'
Saving firewall rules for IPv4 and IPv6...
+ sudo debconf-set-selections
+ echo iptables-persistent iptables-persistent/autosave_v4 boolean true
+ sudo debconf-set-selections
+ echo iptables-persistent iptables-persistent/autosave_v6 boolean true
+ system_install_package iptables-persistent
+ '[' '!' -n iptables-persistent ']'
+ packages=('iptables-persistent')
+ local packages
+ case "${detected_distro['family']}" in
+ DEBIAN_FRONTEND=noninteractive
+ apt-get -y install iptables-persistent -qq
+ exit

it looks like fail2ban is removing ufw and installing iptables so the rule for port 22 is being lost as it is set before iptables is installed

[edit] Actually I don't think fail2ban is removing ufw, because configure_basic_firewall is using iptables, it's the calls it makes to add_port which is trying to use ufw :| but after this runs /usr/sbin/ufw does not exist on the instance

[second edit] From looking into it a bit more save_firewall installs iptables-persistent which results in ufw being removed

root@localhost:~# apt install iptables-persistent
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following additional packages will be installed:
  netfilter-persistent
The following packages will be REMOVED:
  ufw
The following NEW packages will be installed:
  iptables-persistent netfilter-persistent
0 upgraded, 2 newly installed, 1 to remove and 27 not upgraded.
Need to get 14.3 kB of archives.
After this operation, 778 kB disk space will be freed.

so the add_port call because save_firewall uses ufw, but then save_firewall removes ufw

1 Reply

Reply

Please enter an answer
Tips:

You can mention users to notify them: @username

You can use Markdown to format your question. For more examples see the Markdown Cheatsheet.

> I’m a blockquote.

I’m a blockquote.

[I'm a link] (https://www.google.com)

I'm a link

**I am bold** I am bold

*I am italicized* I am italicized

Community Code of Conduct