From 8461b693643177944423e62b35fb2b0582b758fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Imobach=20Gonz=C3=A1lez=20Sosa?= Date: Fri, 9 Feb 2024 08:58:33 +0000 Subject: [PATCH] [doc] Add a document describin the new architecture --- doc/new_architecture.md | 172 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 172 insertions(+) create mode 100644 doc/new_architecture.md diff --git a/doc/new_architecture.md b/doc/new_architecture.md new file mode 100644 index 0000000000..4c7fdbe3fe --- /dev/null +++ b/doc/new_architecture.md @@ -0,0 +1,172 @@ +# Agama's 2024 architecture + +This document describes the proposal for the new Agama architecture. The reasons for introducing +these changes are recorded in [a discussion in Agama's repository][drop-cockpit]. + +[drop-cockpit]: https://github.com/openSUSE/agama/discussions/1000 + +But before describing how the architecture should look, let's quickly look at the current status. + +## The current architecture + +At this point, Agama is composed of three high-level components: + +* **Agama service**: implements the logic to perform the installation. It is the core component of +Agama and it offers a D-Bus interface. Actually, it is composed of two services: `rubygem-agama` and +`agama-dbus-server`. + +* **Web user interface (`cockpit-agama`)**: a web-based interface that plays the role of a GUI when +using Agama live. + +* **Command Line Interface (`agama-cli`)**: it allows to interact with Agama core and drives the +auto-installation process. + +In addition to those components, we need to consider Cockpit, which plays a vital role: + +* It makes communication between the web UI and the D-Bus services possible. +* It makes the web UI code available to the browser. +* It takes care of authenticating the user when connecting remotely. Again, it is only relative to +the web UI. + +```mermaid +flowchart LR + subgraph Clients + Browser + CLI + end + + subgraph Cockpit + UI["Web UI"] + end + + subgraph Agama Service + Rust[Agama Rust] + Ruby[Agama Ruby] + end + + Browser <---> UI + UI <--D-Bus--> Rust + UI <--D-Bus--> Ruby + CLI <--D-Bus--> Rust + CLI <--D-Bus--> Ruby + Rust <--D-Bus---> Ruby +``` + +## The new architecture + +The proposed architecture is not that different from the current one, but it tries to meet these +goals: + +* Drop our dependency on Cockpit. +* Implement a higher-level API to be consumed by the clients, partially replacing the D-Bus. + +### Components + +With those goals in mind, we are considering the following components: + +* **Agama core (old `agama-dbus-server`)**: implements the installation logic. It relies heavily on +the Agama YaST service. + +* **Agama YaST service (old `rubygem-agama`)**: it is written in Ruby and has direct access to YaST +libraries. Complex parts, like storage and software handling, are implemented in this component. + +* **HTTP and WebSocket API**: implements the API the clients should use to communicate with Agama. + +* **Web user interface (old `cockpit-agama`)**: Agama's graphical user interface. The web server +makes this React application available to the browsers. + +* **Command Line Interface (`agama-cli`)**: it allows interaction with Agama core and drives the +auto-installation process. With the new architecture, connecting through the network might be +possible without SSH. + +The following diagram could be better, but it represents the main components and their interactions. + +```mermaid +flowchart LR + subgraph Clients + Browser + CLI + end + + subgraph Agama Core + subgraph Web["Web Server"] + direction TB + UI["Web UI"] + API["HTTP/WS API"] + WS["WebSocket"] + end + + Web <--"Channel?" --> Rust + end + Rust <-- "D-Bus" --> YaST["Agama YaST"] + + Browser --> UI + Browser --> API + Browser <---> WS + CLI --> API + CLI <---> WS +``` + +### The web-based API + +The new web-based API is divided into two different parts: + +* **HTTP/JSON API**: allows clients to execute actions or query Agama. For instance, it could get +the list of available products, request a new storage proposal or start the installation. About the +approach, something REST-like is the most suitable. Switching to GraphQL or gRPC do not seem to be +needed in our case (todo: write why). + +* **WebSocket**: Agama will use WebSockets to notify clients about any relevant event: progress, +configuration changes, etc. The event's format is not defined yet, but a JSON event containing the +`type` and the `payload/details` should be enough[^topics]. + +[^topics]: Ideally, the clients should be able to subscribe to the topics they are interested in. + But that feature can wait. + +### Encryption + +In the case of a remote installation, the communication between the clients and the server must be +encrypted. Connecting to port 80 (HTTP) should redirect the client to port 443 (HTTPS). + +About the certificate, Agama will use a self-signed certificate unless the user injects its own +certificate (through a kernel command line option). + +NOTE: under discussion. + +### Authentication + +The HTTP interface should allow authentication specifying a user and password that will be checked +against PAM. It is not clear yet, but we might need to check whether the logged user has permissions +(most probably through Policy Kit). + +On successful authentication, the server generates a [JSON Web Token][jwt] that the client will +include in the subsequent requests. The web client stores the token in an HTTP-only +cookie[^http-only] and the CLI uses a file with restricted permissions. + +[^http-only] HTTP-only cookies cannot be accessed byt client-side JavaScript. + +#### Skipping the authentication + +When using Agama locally in the installation media, it would be unpleasant to ask for a +user/password. For that reason, there must be a mechanism to skip the authentication step. Agama +Live could run a special service that generates a valid token and injects such a token into the +server, the CLI and the web browser. + +## The (optimistic) plan + +1. Build an HTTP API to access the stuff in `agama-dbus-server`. +2. Rename `agama-dbus-server` to `agama-core`. +3. Move the manager to `agama-core`. +4. Drop `agama-core` D-Bus interface, except the bits required by `rubygem-agama`. +5. Build an HTTP API to access `rubygem-agama`. +6. Adapt the CLI to use the HTTP API. +7. Update `agama-live` to skip the authentication when not needed. +8. Adapt the Web UI to use the HTTP API. + +## Links + +* https://bugzilla.suse.com/show_bug.cgi?id=1219688 +* https://cheatsheetseries.owasp.org/cheatsheets/JSON_Web_Token_for_Java_Cheat_Sheet.html + +[http-auth]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication +[jwt]: https://jwt.io