## 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>
146 lines
4.7 KiB
Markdown
146 lines
4.7 KiB
Markdown
# Web server development notes
|
|
|
|
This document includes some notes about the usage and development of Agama's web server.
|
|
|
|
## Installing Rust and related tools
|
|
|
|
It is recommended to use Rustup to install Rust and related tools. In openSUSE distributions, rustup
|
|
is available as a package. After rustup is installed, you can proceed to install the toolchain:
|
|
|
|
```
|
|
zypper --non-interactive in rustup
|
|
rustup install stable
|
|
```
|
|
|
|
In addition to the Rust compiler, the previous command would install some additionall components
|
|
like `cargo`, `clippy`, `rustfmt`, documentation, etc.
|
|
|
|
Another interesting addition might be
|
|
[cargo-binstall](https://github.com/cargo-bins/cargo-binstall), which allows to install Rust
|
|
binaries. If you are fine with this approach, just run:
|
|
|
|
```
|
|
cargo install cargo-binstall
|
|
```
|
|
|
|
## Setting up PAM
|
|
|
|
The web sever will use [Pluggable Authentication Modules
|
|
(PAM)](https://github.com/linux-pam/linux-pam) for authentication. For that
|
|
reason, you need to copy the `agama` service definition for PAM to `/usr/lib/pam.d`. Otherwise, PAM
|
|
would not know how to authenticate the service:
|
|
|
|
```
|
|
cp share/agama.pam /usr/lib/pam.d/agama
|
|
```
|
|
|
|
For further information, see [Authenticating with PAM](https://doc.opensuse.org/documentation/leap/security/single-html/book-security/index.html#cha-pam).
|
|
|
|
## Running the server
|
|
|
|
> [!NOTE]
|
|
> The web server needs to connect to Agama's D-Bus daemon. So you can either start the Agama service
|
|
> or just start the D-Bus daemon (`sudo bundle exec bin/agamactl -f` from the `service/` directory).
|
|
|
|
You need to run the server as `root`, so you cannot use `cargo run` directly. Instead, just do:
|
|
|
|
```
|
|
$ cargo build
|
|
$ sudo ./target/debug/agama-web-server serve
|
|
```
|
|
|
|
If it fails to compile, please check whether `clang-devel` and `pam-devel` are installed.
|
|
|
|
By default the server uses port 80 and listens on all network interfaces. You
|
|
can use the `--address` option if you want to use a different port or a specific
|
|
network interface:
|
|
|
|
```
|
|
$ sudo ./target/debug/agama-web-server serve --address :::5678
|
|
```
|
|
|
|
Some more examples:
|
|
|
|
- Both IPv6 and IPv4, all interfaces: `--address :::5678`
|
|
- Both IPv6 and IPv4, only local loopback : `--address ::1:5678`
|
|
- IPv4 only, all interfaces: `--address 0.0.0.0:5678`
|
|
- IPv4 only, only local loopback : `--address 127.0.0.1:5678`
|
|
- IPv4, only specific interface: `--address 192.168.1.2:5678` (use the IP
|
|
address of that interface)
|
|
|
|
The server can listen on several addresses, you can use the `--address` option
|
|
multiple times.
|
|
|
|
## Trying the server
|
|
|
|
You can check whether the server is up and running by just performing a ping:
|
|
|
|
```
|
|
$ curl http://localhost/ping
|
|
```
|
|
|
|
### Authentication
|
|
|
|
The web server uses a bearer token for HTTP authentication. You can get the token by providing your
|
|
password to the `/auth` endpoint.
|
|
|
|
```
|
|
$ curl http://localhost/api/auth \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"password": "your-password"}'
|
|
{"token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE3MDg1MTA5MzB9.3HmKAC5u4H_FigMqEa9e74OFAq40UldjlaExrOGqE0U"}⏎
|
|
```
|
|
|
|
Now you can access protected routes by including the token in the header:
|
|
|
|
```
|
|
$ curl -X GET http://localhost/protected \
|
|
-H "Accept: application/json" \
|
|
-H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE3MDg1MTA5MzB9.3HmKAC5u4H_FigMqEa9e74OFAq40UldjlaExrOGqE0U"
|
|
```
|
|
|
|
### Connecting to the websocket
|
|
|
|
You can use `websocat` to connect to the websocket. To install the tool, just run:
|
|
|
|
```
|
|
$ cargo binstall websocat
|
|
```
|
|
|
|
If you did not install `cargo-binstall`, you can do:
|
|
|
|
```
|
|
$ cargo install websocat
|
|
```
|
|
|
|
Now, you can use the following command to connect:
|
|
|
|
```
|
|
$ websocat ws://localhost/ws
|
|
-H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE3MDg1MTA5MzB9.3HmKAC5u4H_FigMqEa9e74OFAq40UldjlaExrOGqE0U"
|
|
```
|
|
|
|
## SSL/TLS (HTTPS) Support
|
|
|
|
The web server supports encrypted communication using the HTTPS protocol.
|
|
|
|
The SSL certificate used by the server can be specified by the `--cert` and
|
|
`--key` command line options which should point to the PEM files:
|
|
|
|
```
|
|
$ sudo ./target/debug/agama-web-server serve --cert certificate.pem --key key.pem
|
|
```
|
|
The certificate is expected in the PEM format, if you have a certificate in
|
|
another format you can convert it using the openSSL tools.
|
|
|
|
If a SSL certificate is not specified via command line then the server generates
|
|
a self-signed certificate. Currently it is only kept in memory and generated
|
|
again at each start.
|
|
|
|
The HTTPS protocol is required for external connections, the HTTP connections
|
|
are automatically redirected to HTTPS. *But it still means that the original
|
|
HTTP communication can be intercepted by an attacker, do not rely on this
|
|
redirection!*
|
|
|
|
For internal connections coming from the same machine (via the
|
|
`http://localhost` URL) the unencrypted HTTP communication is allowed.
|