Skip to content

Commit

Permalink
WIP deployment
Browse files Browse the repository at this point in the history
This work aims to code the installation process to take into account many parameters that are complex to manipulate using shell, but also avoid some dependencies that are only used for the installation process.

This work should also simplify deployment on many distributions, while applying the principle of least privilege.

However, one last question is about the dependency management, as it requires rust, we still need a shell script to install rust toolchains. As capable requires nighly,  and sr requires stable>=1.70, it may requires both toolchains for a clean release binary.
  • Loading branch information
LeChatP committed Sep 3, 2024
1 parent 84f1095 commit 70e7c24
Show file tree
Hide file tree
Showing 17 changed files with 834 additions and 375 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ derivative = "2.2.0"
sha2 = "0.10.8"
sha1 = "0.10.6"
md5 = "0.7.0"
chrono = "0.4.37"
chrono = "0.4.38"
pty-process = "0.4.0"
once_cell = "1.19.0"
pest = "2.7.8"
Expand Down
99 changes: 0 additions & 99 deletions configure.sh

This file was deleted.

12 changes: 6 additions & 6 deletions dependencies.sh
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,16 @@ fi
if command -v apt-get &>/dev/null; then
$PRIV_EXE apt-get update
$PRIV_EXE apt-get install "${YES}" "linux-headers-$(uname -r)" || $PRIV_EXE apt-get install "${YES}" linux-headers-generic
$PRIV_EXE apt-get install "${YES}" linux-tools-common linux-tools-generic "linux-tools-$(uname -r)" || $PRIV_EXE apt-get install "${YES}" bpftool
$PRIV_EXE apt-get install "${YES}" man pkg-config openssl libssl-dev curl gcc llvm clang libcap2 libcap2-bin libcap-dev libcap-ng-dev libelf-dev libpam0g-dev libxml2 libxml2-dev libclang-dev make
$PRIV_EXE apt-get install "${YES}" linux-tools-common linux-tools-generic "linux-tools-$(uname -r)"
$PRIV_EXE apt-get install "${YES}" bpftool man pkg-config openssl libssl-dev curl gcc llvm clang libcap2 libcap2-bin libcap-dev libcap-ng-dev libelf-dev libpam0g-dev libclang-dev make
if [ -n "${DEBUG}" ]; then
$PRIV_EXE apt-get install "${YES}" gdb
fi;
if [ -n "${COV}" ]; then
$PRIV_EXE apt-get install "${YES}" gcovr
fi;
elif command -v yum &>/dev/null; then
$PRIV_EXE yum install ${YES} man pkgconfig openssl-devel curl gcc llvm clang clang-devel libcap libcap-ng elfutils libxml2 libxml2-devel make kernel-headers pam-devel bpftool
$PRIV_EXE yum install ${YES} man pkgconfig openssl-devel curl gcc llvm clang clang-devel libcap libcap-ng elfutils make kernel-headers pam-devel bpftool
if [ -n "${DEBUG}" ]; then
$PRIV_EXE yum install "${YES}" gdb
fi;
Expand All @@ -42,7 +42,7 @@ elif command -v pacman &>/dev/null; then
if [ -n "${YES}" ]; then
NOCONFIRM="--noconfirm"
fi
$PRIV_EXE pacman -S "${NOCONFIRM}" man-db pkgconf openssl curl gcc llvm clang libcap libcap-ng libelf libxml2 linux-headers linux-api-headers make bpf
$PRIV_EXE pacman -S "${NOCONFIRM}" man-db pkgconf openssl curl gcc llvm clang libcap libcap-ng libelf linux-headers linux-api-headers make bpf
if [ -n "${DEBUG}" ]; then
$PRIV_EXE pacman -S "${YES}" gdb
fi;
Expand All @@ -63,8 +63,8 @@ fi

. "$HOME/.cargo/env"

# ask for user to install bpf-linker
cargo install --force bpf-linker bindgen-cli
cargo install --git https://github.com/aya-rs/aya -- aya-tool

echo "dependencies installed. Ready to compile."
echo "dependencies installed. Ready to compile & install."
echo "To install, run: cargo xtask install"
6 changes: 6 additions & 0 deletions xtask/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,9 @@ anyhow = "1.0.86"
clap = { version = "4.5.16", features = ["derive"] }
serde = { version = "1.0.209", features = ["rc"] }
serde_json = "1.0.127"
semver = { version = "1.0.23" }
chrono = "0.4.38"
strum = { version = "0.26.3", features = ["derive"] }
capctl = "0.2.4"
nix = { version = "0.29.0", features = ["user","process", "signal", "fs"] }
glob = "0.3.1"
68 changes: 0 additions & 68 deletions xtask/src/build_ebpf.rs

This file was deleted.

73 changes: 73 additions & 0 deletions xtask/src/ebpf/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
use std::{path::PathBuf, process::Command};

use clap::ValueEnum;
use strum::{Display, EnumString};

use crate::install::{BuildOptions, Profile};

#[derive(Debug, Copy, Clone, Display, EnumString, ValueEnum)]
#[strum(serialize_all = "kebab-case")]
#[clap(rename_all = "kebab-case")]
pub enum EbpfArchitecture {
BpfelUnknownNone,
BpfebUnknownNone,
}

// execute aya-tool generate task_struct >
fn generate_task_struct() -> Result<(), anyhow::Error> {
let output = Command::new("aya-tool")
.args(&["generate", "task_struct"])
.output()?;
// write to file
std::fs::write("capable-ebpf/src/vmlinux.rs", output.stdout)?;
Ok(())
}

/// Build the project
pub fn build(opts: &BuildOptions) -> Result<(), anyhow::Error> {
let toolchain = format!("+{}", opts.toolchain.to_string());
let mut args = vec![ toolchain.as_str(), "build", "--package", "capable"];
if opts.profile.is_release() {
args.push("--release")
}
let status = Command::new("cargo")
.args(&args)
.status()
.expect("failed to build userspace");
assert!(status.success());
Ok(())
}



pub fn build_ebpf(ebpf_target: &EbpfArchitecture, profile: &Profile) -> Result<(), anyhow::Error> {

generate_task_struct()?;
let dir = PathBuf::from("capable-ebpf");
let target = format!("--target={}", ebpf_target);
let mut args = vec![
"build",
"--verbose",
target.as_str(),
"-Z",
"build-std=core",
];
if profile.is_release() {
args.push("--release")
}

// Command::new creates a child process which inherits all env variables. This means env
// vars set by the cargo xtask command are also inherited. RUSTUP_TOOLCHAIN is removed
// so the rust-toolchain.toml file in the -ebpf folder is honored.

let status = Command::new("cargo")
.current_dir(dir)
.env_remove("RUSTUP_TOOLCHAIN")
.args(&args)
.status()
.expect("failed to build bpf program");
assert!(status.success());
Ok(())
}


21 changes: 21 additions & 0 deletions xtask/src/ebpf/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
use anyhow::Context;
use build::{build_ebpf, build};
use run::RunOptions;

use crate::install::BuildOptions;

pub mod build;
pub mod run;



pub fn build_all(opts: &BuildOptions) -> Result<(), anyhow::Error> {
build_ebpf(&opts.ebpf, &opts.profile).context("Error while building eBPF program")?;
build(opts).context("Error while building userspace application")
}

pub fn run(opts: &RunOptions) -> Result<(), anyhow::Error> {
build_all(&opts.build)?;
run::run(opts)?;
Ok(())
}
44 changes: 44 additions & 0 deletions xtask/src/ebpf/run.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
use std::process::Command;

use clap::Parser;

use crate::install::BuildOptions;

#[derive(Debug, Parser)]
pub struct RunOptions {
/// Build options
#[clap(flatten)]
pub build: BuildOptions,
/// The command used to wrap capable, sr by default (sudo or doas are not recommended)
#[clap(short, long, default_value = "sr")]
pub runner: String,
/// Arguments to pass to your application
#[clap(name = "args", last = true)]
pub run_args: Vec<String>,
}

/// Build and run the project
pub fn run(opts: &RunOptions) -> Result<(), anyhow::Error> {

// profile we are building (release or debug)
let bin_path = format!("target/{}/capable",opts.build.profile);

// arguments to pass to the application
let mut run_args: Vec<_> = opts.run_args.iter().map(String::as_str).collect();

// configure args
let mut args: Vec<_> = opts.runner.trim().split_terminator(' ').collect();
args.push(bin_path.as_str());
args.append(&mut run_args);

// run the command
let status = Command::new(args.first().expect("No first argument"))
.args(args.iter().skip(1))
.status()
.expect("failed to run the command");

if !status.success() {
anyhow::bail!("Failed to run `{}`", args.join(" "));
}
Ok(())
}
Loading

0 comments on commit 70e7c24

Please sign in to comment.