agama/rust/share/agama-web-server.sh
Ladislav Slezák 078af95a65
Optionally disable remote access (#3269)
## Problem

- https://jira.suse.com/browse/AGM-153
- For security reasons it should be possible to disable remote access to
the Agama web server. A server which is not reachable cannot be hacked.
😃

## Solution

- Add a new `inst.listen_on` boot option, the possible values:
- `inst.listen_on=all` - listen on all network interfaces (allow local
and remote access). This is the default behavior used even without the
`inst.listen_on` option, added just for completeness.
- `inst.listen_on=localhost` - listen only on loop back (localhost)
device. This disables remote access, Agama can be accessed only locally.
- `inst.listen_on=<ip>` - listen on the specified IP address. Both IPv4
and IPv6 addresses are supported. It is possible to use multiple IP
addresses separated by comma. Addresses not found in the system are
ignored.
- `inst.listen_on=<interface>` - listen on the specified network
interface. Multiple interfaces can be separated by comma. Not found
interfaces are ignored.

Agama always listens on the local loop back interface even when
specifying a specific network interface or IP address for listening. The
reason is to avoid reporting connection errors by the Firefox started in
the Live ISO.

## Details

- The `--address2` CLI option has been removed, instead it is possible
to specify `--address` option multiple times.
- The PR includes the @mvidner's patch
https://github.com/agama-project/agama/pull/3111 - fallback to an IPv4
address when listening to IPv6 address fails (when IPv6 is disabled with
the `ipv6.disable=1` boot option)
- Added the `agama-web-server.sh` wrapper script started from the
systemd service. It evaluates the boot parameters and builds the address
parameters for the Agama server.

## Notes

- The other network services like SSH can be disabled using the standard
`systemd.mask` boot option. For example to disable the SSH service use
this boot option: `systemd.mask=sshd.service`. (I'll document this as
well...)

## Testing

- Tested manually in all scenarios: with disabled remote access,
listening on the specified IPv6 (including link local address) or IPv4
address, listening on specified interface, listening on multiple
interfaces
- Tested Martin's patch with the `ipv6.disable=1` boot option, Agama
properly listens on the IPv4 addresses in that case.

---------

Co-authored-by: Martin Vidner <mvidner@suse.com>
2026-03-12 14:12:15 +01:00

97 lines
3.8 KiB
Bash
Executable file

#!/usr/bin/bash
#
# Copyright (c) [2026] SUSE LLC
#
# All Rights Reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, contact SUSE LLC.
#
# To contact SUSE LLC about this file by physical or electronic mail, you may
# find current contact information at www.suse.com.
# This script is a wrapper for the Agama web server, it evaluates to which
# addresses the server should listen to.
if [[ "$1" == "-h" || "$1" == "--help" ]]; then
echo "Usage: $0"
echo
echo " This is a wrapper script for the Agama web server (agama-web-server)."
echo
echo " It configures the listening addresses for the web server based on"
echo " the \"inst.listen_on\" boot option."
exit 0
fi
# the default options: listen on all interfaces for both HTTP and HTTPS ports,
# the IPv4 addresses are fallbacks when IPv6 is disabled with the
# "ipv6.disable=1" kernel boot option
DEFAULT_OPTIONS=(--address ":::80,0.0.0.0:80" --address ":::443,0.0.0.0:443")
# options for localhost access only
LOCAL_OPTIONS=(--address "::1:80,127.0.0.1:80" --address "::1:443,127.0.0.1:443")
# check if the "inst.listen_on=" boot option was used
if grep -q "\binst.listen_on=.\+" /run/agama/cmdline.d/agama.conf; then
LISTEN_ON=$(grep "\binst.listen_on=.\+" /run/agama/cmdline.d/agama.conf | sed 's/.*\binst.listen_on=\([^[:space:]]\+\)/\1/')
if [ "$LISTEN_ON" = "localhost" ]; then
OPTIONS=("${LOCAL_OPTIONS[@]}")
elif [ "$LISTEN_ON" = "all" ]; then
OPTIONS=("${DEFAULT_OPTIONS[@]}")
else
# always run on the localhost
OPTIONS=("${LOCAL_OPTIONS[@]}")
# the string can contain multiple addresses separated by comma,
# replace commas with spaces and iterate over items
ADDRESSES=${LISTEN_ON//,/ }
for ADDRESS in $ADDRESSES; do
# check if the value is an IP address (IPv6, IPv6 link local or IPv4)
if echo "$ADDRESS" | grep -qE '^[0-9a-fA-F:]+$|^[fF][eE]80|^([0-9]{1,3}\.){3}[0-9]{1,3}$'; then
echo "<5>Listening on IP address ${ADDRESS}"
OPTIONS+=(--address "${ADDRESS}:80" --address "${ADDRESS}:443")
else
# otherwise assume it is as an interface name
if ip addr show dev "${ADDRESS}" >/dev/null 2>&1; then
# find the IP address for the specified interface
IP_ADDRS=$(ip -o addr show dev "${ADDRESS}" | awk '{print $4}' | cut -d/ -f1)
if [ -n "${IP_ADDRS}" ]; then
for IP in $IP_ADDRS; do
# append the %device for link local IPv6 addresses
if [[ "$IP" == fe80* ]]; then
IP="${IP}%${ADDRESS}"
fi
echo "<5>Listening on interface ${ADDRESS} with IP address ${IP}"
OPTIONS+=(--address "${IP}:80" --address "${IP}:443")
done
else
echo "<3>IP address for interface ${ADDRESS} not found"
fi
else
echo "<3>Network Interface ${ADDRESS} not found"
fi
fi
done
fi
else
OPTIONS=("${DEFAULT_OPTIONS[@]}")
fi
if [ "${OPTIONS[*]}" = "${DEFAULT_OPTIONS[*]}" ]; then
echo "<5>Listening on all network interfaces"
elif [ "${OPTIONS[*]}" = "${LOCAL_OPTIONS[*]}" ]; then
echo "<5>Disabling remote access to the Agama web server"
fi
echo "<5>Starting Agama web server with options: ${OPTIONS[*]}"
exec /usr/bin/agama-web-server serve "${OPTIONS[@]}"