From d2880b051c87ac5fa201fef1d85fc804abdf974d 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 1/5] [doc] Add a document describing 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 From 93c7c6ea73805cc26b6cf50e18d1f1750a283104 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Imobach=20Gonz=C3=A1lez=20Sosa?= Date: Fri, 9 Feb 2024 19:28:29 +0000 Subject: [PATCH 2/5] [doc] Remove the list of tasks --- doc/new_architecture.md | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/doc/new_architecture.md b/doc/new_architecture.md index 4c7fdbe3fe..5be0092d26 100644 --- a/doc/new_architecture.md +++ b/doc/new_architecture.md @@ -152,17 +152,6 @@ user/password. For that reason, there must be a mechanism to skip the authentica 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 From 14226861eaa6c9efff06ce1ff9ebedb89aac624c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Imobach=20Gonz=C3=A1lez=20Sosa?= Date: Mon, 12 Feb 2024 08:53:38 +0000 Subject: [PATCH 3/5] Updates from doc review --- doc/new_architecture.md | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/doc/new_architecture.md b/doc/new_architecture.md index 5be0092d26..500cb7019b 100644 --- a/doc/new_architecture.md +++ b/doc/new_architecture.md @@ -9,7 +9,7 @@ But before describing how the architecture should look, let's quickly look at th ## The current architecture -At this point, Agama is composed of three high-level components: +At this point, Agama is composed of four 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 @@ -21,6 +21,9 @@ using Agama live. * **Command Line Interface (`agama-cli`)**: it allows to interact with Agama core and drives the auto-installation process. +* **Auto-installation (`autoinstallation`)**: it is composed by a Systemd service (`agama-auto`) and +an script that relies in `agama-cli`. + 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. @@ -58,7 +61,8 @@ The proposed architecture is not that different from the current one, but it tri goals: * Drop our dependency on Cockpit. -* Implement a higher-level API to be consumed by the clients, partially replacing the D-Bus. +* Implement a higher-level API to be consumed by the clients, replacing D-Bus for client-server +communication. Agama will still use D-Bus for IPC between the Rust and Ruby components. ### Components @@ -71,11 +75,12 @@ the Agama YaST service. 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. +Under the hood, it still uses D-Bus for communication between Agama core and Agama YaST. * **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 +* **Command Line Interface (`agama-cli`)**: it allows interaction with Agama and drives the auto-installation process. With the new architecture, connecting through the network might be possible without SSH. @@ -137,7 +142,7 @@ NOTE: under discussion. 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). +(most probably through Polkit). 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 From bd5bd5a5abdbf9e2d82d69d065520250ef3015dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Imobach=20Gonz=C3=A1lez=20Sosa?= Date: Mon, 12 Feb 2024 09:39:33 +0000 Subject: [PATCH 4/5] Update from code review --- doc/new_architecture.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/new_architecture.md b/doc/new_architecture.md index 500cb7019b..a9b7238285 100644 --- a/doc/new_architecture.md +++ b/doc/new_architecture.md @@ -142,7 +142,7 @@ NOTE: under discussion. 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 Polkit). +(making sure it is `root` or through Polkit). 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 From 60de0742af200f51cf8b390fb7f06585e663ec43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Imobach=20Gonz=C3=A1lez=20Sosa?= Date: Mon, 12 Feb 2024 09:56:22 +0000 Subject: [PATCH 5/5] Update from code review --- doc/new_architecture.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/doc/new_architecture.md b/doc/new_architecture.md index a9b7238285..a0d9b087e6 100644 --- a/doc/new_architecture.md +++ b/doc/new_architecture.md @@ -22,7 +22,7 @@ using Agama live. auto-installation process. * **Auto-installation (`autoinstallation`)**: it is composed by a Systemd service (`agama-auto`) and -an script that relies in `agama-cli`. +a script that relies on `agama-cli`. In addition to those components, we need to consider Cockpit, which plays a vital role: @@ -36,6 +36,7 @@ flowchart LR subgraph Clients Browser CLI + auto end subgraph Cockpit @@ -53,6 +54,7 @@ flowchart LR CLI <--D-Bus--> Rust CLI <--D-Bus--> Ruby Rust <--D-Bus---> Ruby + auto --> CLI ``` ## The new architecture @@ -84,6 +86,9 @@ makes this React application available to the browsers. auto-installation process. With the new architecture, connecting through the network might be possible without SSH. +* **Auto-installation (`autoinstallation`)**: as in the current architecture, it is composed by +a Systemd service (`agama-auto`) and a script that relies on `agama-cli`. + The following diagram could be better, but it represents the main components and their interactions. ```mermaid @@ -91,6 +96,7 @@ flowchart LR subgraph Clients Browser CLI + auto end subgraph Agama Core @@ -101,7 +107,7 @@ flowchart LR WS["WebSocket"] end - Web <--"Channel?" --> Rust + Web <--"Channel" --> Rust end Rust <-- "D-Bus" --> YaST["Agama YaST"] @@ -110,6 +116,7 @@ flowchart LR Browser <---> WS CLI --> API CLI <---> WS + auto --> CLI ``` ### The web-based API