From dfa3a344849312d97e2c366845549e8f966a9d98 Mon Sep 17 00:00:00 2001 From: JMARyA Date: Fri, 10 Jan 2025 13:19:39 +0100 Subject: [PATCH] refactor + firewall --- Cargo.lock | 25 ++++++++++++++++ Cargo.toml | 1 + installs/desktop.toml | 32 +------------------- installs/full.toml | 8 +++++ installs/min.toml | 21 +------------ installs/server.toml | 45 +--------------------------- src/config.rs | 6 ++-- src/install/drives.rs | 63 +++++++++++++++++++++++++++++++++++++-- src/install/firewall.rs | 21 +++++++++++++ src/install/first_boot.rs | 9 +++++- src/install/gpu.rs | 22 ++++++++++---- src/install/mod.rs | 13 +++++--- src/install/ssh.rs | 9 +++++- src/install/user.rs | 5 +++- src/install/virt.rs | 19 ++++++++++-- src/pkg.rs | 9 ++---- src/print.rs | 15 ++++++++-- 17 files changed, 200 insertions(+), 123 deletions(-) create mode 100644 src/install/firewall.rs diff --git a/Cargo.lock b/Cargo.lock index d4efc4f..ef13355 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -130,6 +130,12 @@ version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" +[[package]] +name = "itoa" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" + [[package]] name = "libc" version = "0.2.169" @@ -149,6 +155,7 @@ dependencies = [ "clap", "nix", "serde", + "serde_json", "toml", "yansi", ] @@ -183,6 +190,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + [[package]] name = "serde" version = "1.0.216" @@ -203,6 +216,18 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.135" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b0d7ba2887406110130a978386c4e1befb98c674b4fba677954e4db976630d9" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + [[package]] name = "serde_spanned" version = "0.6.8" diff --git a/Cargo.toml b/Cargo.toml index 8cff2a4..490c9a6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,5 +7,6 @@ edition = "2024" clap = { version = "4.5.23", features = ["cargo"] } nix = { version = "0.29.0", features = ["user"] } serde = { version = "1.0.216", features = ["derive"] } +serde_json = "1.0.135" toml = "0.8.19" yansi = "1.0.1" diff --git a/installs/desktop.toml b/installs/desktop.toml index 75c08ce..c59366a 100644 --- a/installs/desktop.toml +++ b/installs/desktop.toml @@ -1,59 +1,29 @@ # Desktop Install Template -# Drive Selection for Install [drive] -# Device node for the EFI boot filesystem boot = "/dev/null" - -# Device node for the root filesystem root = "/dev/null" - -# Root filesystem encryption passphrase -# If this option is set the root filesystem will be encrypted with LUKS encryption = "password" -# General configuration [general] -# Preset mode = "Desktop" - -# System Locale locale = "de_DE.UTF-8" - -# Keymap keyboard_layout = "de" keyboard_variant = "mac" - -# Timezone timezone = "Europe/Berlin" - -# Hostname hostname = "navos" - -# Root password root_password = "root" - -# Enable Bluetooth bluetooth = true - -# GPU Video Drivers gpu_driver = "NVIDIA" +firewall = true [pkg] -# Additional packages pkg = [ "nano", "micro" ] -# User configuration -# The `[[user]]` directive can be repeated to create multiple users. [[user]] -# Username name = "u" - -# User password password = "pass" - -# Add user to wheel group wheel = true diff --git a/installs/full.toml b/installs/full.toml index 85e39b8..48c7839 100644 --- a/installs/full.toml +++ b/installs/full.toml @@ -15,6 +15,10 @@ encryption = "password" # General configuration [general] # Preset +# Available options: +# - `Base`: Basic Arch Linux Installation +# - `Desktop`: navOS Desktop Installation +# - `Server`: navOS Server Installation mode = "Desktop" # System Locale @@ -37,8 +41,12 @@ root_password = "root" bluetooth = true # GPU Video Drivers +# Available options: `NVIDIA`, `AMD`, `INTEL` gpu_driver = "NVIDIA" +# Enable firewall +firewall = true + [pkg] # Additional packages pkg = [ diff --git a/installs/min.toml b/installs/min.toml index e2185ab..7b905c4 100644 --- a/installs/min.toml +++ b/installs/min.toml @@ -1,38 +1,19 @@ # Minimal Install Template -# Drive Selection for Install [drive] -# Device node for the EFI boot filesystem boot = "/dev/null" - -# Device node for the root filesystem root = "/dev/null" - -# Root filesystem encryption passphrase -# If this option is set the root filesystem will be encrypted with LUKS encryption = "password" -# General configuration [general] -# Preset mode = "Base" - -# System Locale locale = "de_DE.UTF-8" - -# Keymap keyboard_layout = "de" keyboard_variant = "mac" - -# Timezone timezone = "Europe/Berlin" - -# Hostname hostname = "navos_min" - -# Root password root_password = "root" +firewall = false [pkg] -# Additional packages pkg = [] diff --git a/installs/server.toml b/installs/server.toml index 67a33b4..58fec8a 100644 --- a/installs/server.toml +++ b/installs/server.toml @@ -1,79 +1,36 @@ # Server Install Template -# Drive Selection for Install [drive] -# Device node for the EFI boot filesystem boot = "/dev/null" - -# Device node for the root filesystem root = "/dev/null" - -# Root filesystem encryption passphrase -# If this option is set the root filesystem will be encrypted with LUKS encryption = "password" -# General configuration [general] -# Preset mode = "Server" - -# System Locale locale = "de_DE.UTF-8" - -# Keymap keyboard_layout = "de" keyboard_variant = "mac" - -# Timezone timezone = "Europe/Berlin" - -# Hostname hostname = "navos" - -# Root password root_password = "root" +firewall = true [pkg] -# Additional packages pkg = [] -# Enable virtualization virtualization = true - -# Enable docker docker = true -# User configuration -# The `[[user]]` directive can be repeated to create multiple users. [[user]] -# Username name = "u" - -# User password password = "pass" - -# Add user to wheel group wheel = true - -# Add user to Docker group docker = true - -# Add user to libvirt group virtualization = true -# SSH Configuration -# If `[ssh]` is set, openssh will be installed and enabled. [ssh] -# Config file for sshd -# This file will be copied to the new system sshd_config = "/etc/ssh/sshd_config" -# Install a SSH keys -# To set multiple keys, repeat the `[[ssh.key]]` directive. -# Every key will be installed in the users respective `authorized_keys` file. [[ssh.key]] -# The SSH Key key = "ssh-rsa ... user@host" - -# The users allowed to login with this key users = ["u", "root"] diff --git a/src/config.rs b/src/config.rs index 2b4b301..95372c2 100644 --- a/src/config.rs +++ b/src/config.rs @@ -88,14 +88,16 @@ pub struct GeneralConfig { // Enable Bluetooth pub bluetooth: Option, /// Install Video Driver - pub gpu_driver: Option + pub gpu_driver: Option, + // Eanble firewall + pub firewall: Option, } #[derive(Debug, Clone, Deserialize)] pub enum GPUVendor { AMD, NVIDIA, - INTEL + INTEL, } #[derive(Debug, Clone, Deserialize)] diff --git a/src/install/drives.rs b/src/install/drives.rs index e95bde2..2d4160a 100644 --- a/src/install/drives.rs +++ b/src/install/drives.rs @@ -1,10 +1,13 @@ -use crate::{config::DriveConfig, linux::run_command}; +use yansi::{Color, Paint}; + +use crate::{config::DriveConfig, linux::run_command, print_status}; // TODO : Add support for using entire block device /// Format the drives with the given config pub fn format_drives(conf: &DriveConfig) { - // TODO : Safety checks !!! + disk_safe_check(&conf.root); + disk_safe_check(&conf.root); // EFI (BOOT) run_command(&["mkfs.vfat", "-F", "32", conf.boot.as_str()], None, false); @@ -52,3 +55,59 @@ pub fn mount_drives(conf: &DriveConfig) { false, ); } + +/// Format a disk with EFI and BOOT partitions. +pub fn partition_disk(dev: &str) { + disk_safe_check(dev); + print_status(&format!("Formatting disk {dev}")); + let cmd = vec!["fdisk", dev]; + let input = "g\nn\n1\n\n+1G\nt\n1\nn\n2\n\nw\n"; + run_command(&cmd, Some(input), false); +} + +/// Check if `dev` contains a filesystem and error if it does +pub fn disk_safe_check(dev: &str) { + if let Some(fs) = has_filesystem(dev) { + println!( + "{} Device {} already contains a filesystem {}", + "Error:".paint(Color::Red), + dev.paint(Color::Red), + fs.paint(Color::Blue) + ); + std::process::exit(1); + } +} + +pub fn has_filesystem(dev: &str) -> Option { + let blockdevs: serde_json::Value = + serde_json::from_str(&run_command(&["lsblk", "--fs", "--json"], None, false).0).unwrap(); + + // TODO : Follow if symlink from /dev/disks + let dev = dev.trim_start_matches("/dev/"); + + let dev_entry = blockdevs + .as_object() + .unwrap() + .get("blockdevices") + .unwrap() + .as_array() + .unwrap() + .iter() + .find(|x| { + x.as_object() + .unwrap() + .get("name") + .unwrap() + .as_str() + .unwrap() + == dev + }); + + if let Some(dev_entry) = dev_entry { + if let Some(fs) = dev_entry.as_object().unwrap().get("fstype") { + return Some(fs.to_string()); + } + } + + None +} diff --git a/src/install/firewall.rs b/src/install/firewall.rs new file mode 100644 index 0000000..aea7f2c --- /dev/null +++ b/src/install/firewall.rs @@ -0,0 +1,21 @@ +use crate::{ + linux::{arch_chroot, systemd_service_enable}, + pkg::install_pkgs, + print_status, +}; + +pub fn setup_firewall(ssh: bool) { + print_status("Enabling firewall"); + install_pkgs(&["ufw"]); + systemd_service_enable("ufw.service"); + + arch_chroot(&["ufw", "default", "deny"], None, false); + + if ssh { + arch_chroot(&["ufw", "allow", "22/tcp"], None, false); + + arch_chroot(&["ufw", "limit", "ssh"], None, false); + } + + arch_chroot(&["ufw", "enable"], None, false); +} diff --git a/src/install/first_boot.rs b/src/install/first_boot.rs index d59bcf6..bae4650 100644 --- a/src/install/first_boot.rs +++ b/src/install/first_boot.rs @@ -45,7 +45,14 @@ pub fn first_boot_values(conf: &GeneralConfig) { print_status("Writing /etc/hostname"); std::fs::write("/mnt/etc/hostname", format!("{}\n", conf.hostname)).unwrap(); - install_file("/mnt/etc/hosts", &format!("127.0.0.1 localhost\n::1 localhost\n127.0.1.1 {}\n", conf.hostname), 0o644); + install_file( + "/mnt/etc/hosts", + &format!( + "127.0.0.1 localhost\n::1 localhost\n127.0.1.1 {}\n", + conf.hostname + ), + 0o644, + ); // LOCALE print_status("Setting locale"); diff --git a/src/install/gpu.rs b/src/install/gpu.rs index 73e5cca..0e872f7 100644 --- a/src/install/gpu.rs +++ b/src/install/gpu.rs @@ -3,13 +3,25 @@ use crate::{config::GPUVendor, pkg::install_pkgs}; pub fn setup_video_drivers(vendor: &GPUVendor) { match vendor { GPUVendor::AMD => { - install_pkgs(&["xf86-video-amdgpu", "mesa", "lib32-mesa", "vulkan-radeon", "lib32-vulkan-radeon"]); - }, + install_pkgs(&[ + "xf86-video-amdgpu", + "mesa", + "lib32-mesa", + "vulkan-radeon", + "lib32-vulkan-radeon", + ]); + } GPUVendor::NVIDIA => { install_pkgs(&["nvidia", "nvidia-utils", "lib32-nvidia-utils"]); - }, + } GPUVendor::INTEL => { - install_pkgs(&["xf86-video-intel2", "mesa", "lib32-mesa", "vulkan-intel", "lib32-vulkan-intel"]); - }, + install_pkgs(&[ + "xf86-video-intel2", + "mesa", + "lib32-mesa", + "vulkan-intel", + "lib32-vulkan-intel", + ]); + } } } diff --git a/src/install/mod.rs b/src/install/mod.rs index 3ac2c15..b44cbf3 100644 --- a/src/install/mod.rs +++ b/src/install/mod.rs @@ -1,6 +1,5 @@ // TODO : Autojoin docker swarm // TODO : Autojoin teleport -// TODO : Firewall // DRIVE SELECTION @@ -9,6 +8,7 @@ use boot::setup_bootloader; use desktop::setup_desktop; use docker::setup_docker; use drives::{format_drives, mount_drives}; +use firewall::setup_firewall; use firmware::{setup_fwupd, setup_microcode}; use first_boot::{first_boot_values, genfstab}; use gpu::setup_video_drivers; @@ -28,7 +28,10 @@ pub mod boot; pub mod desktop; pub mod docker; pub mod drives; +pub mod firewall; +pub mod firmware; pub mod first_boot; +pub mod gpu; pub mod kernel; pub mod navos; pub mod ollama; @@ -38,8 +41,6 @@ pub mod ssh; pub mod user; pub mod virt; pub mod zram; -pub mod firmware; -pub mod gpu; use crate::{ config::InstallConfig, @@ -142,6 +143,10 @@ pub fn install(conf: InstallConfig) { setup_bluetooth(); } + if conf.general.firewall.unwrap_or(true) { + setup_firewall(conf.ssh.is_some()); + } + setup_vm(); if let Some(gpu_vendor) = &conf.general.gpu_driver { setup_video_drivers(gpu_vendor); @@ -155,5 +160,5 @@ pub fn install(conf: InstallConfig) { setup_tpm_unlock(&conf.drive); } - println!("{}", "System install complete".paint(Color::Green)); + println!("{}", "System install complete".bold().paint(Color::Green)); } diff --git a/src/install/ssh.rs b/src/install/ssh.rs index 1157df9..0af5f65 100644 --- a/src/install/ssh.rs +++ b/src/install/ssh.rs @@ -1,4 +1,9 @@ -use crate::{config::SSHConfig, linux::install_file, pkg::install_pkgs, print_status}; +use crate::{ + config::SSHConfig, + linux::{install_file, systemd_service_enable}, + pkg::install_pkgs, + print_status, +}; use std::io::Write; /// Setup SSH on the system @@ -34,5 +39,7 @@ pub fn setup_ssh(conf: &Option) { writeln!(authorized_keys, "{}\n", key.key).unwrap(); } } + + systemd_service_enable("sshd.service"); } } diff --git a/src/install/user.rs b/src/install/user.rs index b463a74..3ff7ad7 100644 --- a/src/install/user.rs +++ b/src/install/user.rs @@ -1,5 +1,8 @@ use crate::{ - config::UserConfig, linux::{arch_chroot, install_file}, pkg::install_pkgs, print_status + config::UserConfig, + linux::{arch_chroot, install_file}, + pkg::install_pkgs, + print_status, }; pub fn change_passwd(user: &str, pw: &str) { diff --git a/src/install/virt.rs b/src/install/virt.rs index 78757fe..1fc228c 100644 --- a/src/install/virt.rs +++ b/src/install/virt.rs @@ -1,7 +1,7 @@ use crate::{ config::{InstallConfig, InstallMode}, - linux::{arch_chroot, systemd_service_enable}, - pkg::install_pkgs, + linux::{arch_chroot, run_command, systemd_service_enable}, + pkg::install_pkgs, print_status, }; pub fn setup_virtualization(conf: &InstallConfig) { @@ -30,6 +30,19 @@ pub fn setup_virtualization(conf: &InstallConfig) { } } +/// Setup guest utils if running inside a VM pub fn setup_vm() { - // TODO : Install guest tools if in virt with systemd-detect-virt + let is_vm = run_command(&[ + "systemd-detect-virt", "--vm" + ], None, false).0.trim(); + + match is_vm { + "qemu" | "kvm" => { + print_status("Detected KVM. Installing utils"); + install_pkgs(&["qemu-guest-agent", "spice-vdagent"]); + systemd_service_enable("qemu-guest-agent.service"); + systemd_service_enable("spice-vdagentd.service"); + }, + _ => {} + } } diff --git a/src/pkg.rs b/src/pkg.rs index 479412e..5604561 100644 --- a/src/pkg.rs +++ b/src/pkg.rs @@ -3,18 +3,16 @@ use crate::{ linux::{arch_chroot, run_command}, }; -pub const DESKTOP_PKG: [&str; 16] = [ +pub const DESKTOP_PKG: [&str; 17] = [ // Desktop "plasma", "sddm", - // Sound "pipewire", "pipewire-alsa", "pipewire-pulse", "pipewire-jack", "wireplumber", - // Applications "konsole", "dolphin", @@ -24,9 +22,9 @@ pub const DESKTOP_PKG: [&str; 16] = [ "gwenview", "ark", "flatpak", - // Misc - "navos/navos" + "navos/navos", + "man", ]; pub const SERVER_PKG: [&str; 2] = ["tmux", "navos/navos"]; @@ -60,7 +58,6 @@ pub fn pacstrap(conf: &PackageConfig) { "zsh", "zsh-completions", "zsh-autosuggestions", - "man" ]; cmd.extend( diff --git a/src/print.rs b/src/print.rs index efa6877..1719aa1 100644 --- a/src/print.rs +++ b/src/print.rs @@ -65,11 +65,20 @@ pub fn print_config(conf: &InstallConfig) { } if let Some(vendor) = &conf.general.gpu_driver { match vendor { - crate::config::GPUVendor::AMD => general_info.add_str(format!("🟥 AMD GPU {}", "✔️".paint(Color::Green))), - crate::config::GPUVendor::INTEL => general_info.add_str(format!("🟦 Intel GPU {}", "✔️".paint(Color::Green))), - crate::config::GPUVendor::NVIDIA => general_info.add_str(format!("🟩 NVIDIA GPU {}", "✔️".paint(Color::Green))), + crate::config::GPUVendor::AMD => { + general_info.add_str(format!("🟥 AMD GPU {}", "✔️".paint(Color::Green))) + } + crate::config::GPUVendor::INTEL => { + general_info.add_str(format!("🟦 Intel GPU {}", "✔️".paint(Color::Green))) + } + crate::config::GPUVendor::NVIDIA => { + general_info.add_str(format!("🟩 NVIDIA GPU {}", "✔️".paint(Color::Green))) + } } } + if conf.general.firewall.unwrap_or(true) { + general_info.add_str(format!("🔥 Firewall {}", "✔️".paint(Color::Green))); + } root_info.add_tree("🔨 General", general_info);