1
0
Fork 0

Add metadata in command, add whitelist, add daemon config

This commit is contained in:
Florian RICHER 2023-02-04 14:33:57 +01:00
parent 482dd830dc
commit 46d401493b
9 changed files with 123 additions and 16 deletions

32
Cargo.lock generated
View file

@ -2,6 +2,15 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "aho-corasick"
version = "0.7.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac"
dependencies = [
"memchr",
]
[[package]]
name = "anyhow"
version = "1.0.68"
@ -121,8 +130,10 @@ name = "command_gateway"
version = "0.1.0"
dependencies = [
"prost",
"regex",
"serde",
"serde_json",
"serde_yaml",
"tokio",
"tokio-stream",
"tonic",
@ -613,6 +624,8 @@ version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
@ -674,6 +687,19 @@ dependencies = [
"serde",
]
[[package]]
name = "serde_yaml"
version = "0.9.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fb06d4b6cdaef0e0c51fa881acb721bed3c924cfaa71d9c94a3b771dfdf6567"
dependencies = [
"indexmap",
"itoa",
"ryu",
"serde",
"unsafe-libyaml",
]
[[package]]
name = "slab"
version = "0.4.7"
@ -939,6 +965,12 @@ version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc"
[[package]]
name = "unsafe-libyaml"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc7ed8ba44ca06be78ea1ad2c3682a43349126c8818054231ee6f4748012aed2"
[[package]]
name = "uuid"
version = "1.2.2"

View file

@ -21,6 +21,8 @@ path = "src/interpreter/main.rs"
[dependencies]
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
serde_yaml = "0.9"
regex = "1.7"
uuid = { version = "1.2.2", features = [
"v4", # Lets you generate random UUIDs
"fast-rng", # Use a faster (but still sufficiently random) RNG

View file

@ -10,18 +10,16 @@ service Unix {
}
message AuthorizeRequest {
// identifier of the project
string identifier = 1;
// ssh_keys from ssh agent
string token = 2;
// command like /bin/bash
string command = 3;
// json like argument
string command_arg = 1;
// pid
uint32 pid = 4;
uint32 pid = 2;
}
message AuthorizeResponse {
string session_id = 2;
string session_id = 1;
// json like arguments changed by daemon
string command_arg = 2;
}
message TerminateRequest {

View file

@ -3,11 +3,10 @@ use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize, Debug)]
pub struct Command {
pub identifier: String,
pub token: String,
pub command: String,
pub envs: HashMap<String, String>,
pub args: Vec<String>
pub args: Vec<String>,
pub metadata: HashMap<String, String>,
}
impl Into<std::process::Command> for Command {
@ -19,4 +18,21 @@ impl Into<std::process::Command> for Command {
command.envs(self.envs);
command
}
}
impl From<&str> for Command {
fn from(value: &str) -> Self {
serde_json::from_str(value).unwrap_or_default()
}
}
impl Default for Command {
fn default() -> Self {
Self {
command: "/bin/nologin".into(),
envs: HashMap::default(),
args: Vec::default(),
metadata: HashMap::default(),
}
}
}

View file

@ -0,0 +1,14 @@
mod whitelist;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Default)]
pub struct Configuration {
whitelist: whitelist::Whitelist,
}
impl Configuration {
pub fn command_allowed(&self, command: &str) -> bool {
self.whitelist == command
}
}

View file

@ -0,0 +1,45 @@
use regex::Regex;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Default, Debug)]
pub struct Whitelist(Vec<String>);
impl PartialEq<&str> for Whitelist {
fn eq(&self, other: &&str) -> bool {
self.0.iter().any(|w| {
match Regex::new(w) {
Ok(regex) => regex.is_match(other),
Err(_) => w == other
}
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_should_return_true_if_exact_value() {
let w = Whitelist(vec!["/usr/bin/bash".into()]);
assert_eq!(w, "/usr/bin/bash");
}
#[test]
fn test_should_return_false_if_no_exact_value() {
let w = Whitelist(vec!["/usr/bin/bash".into()]);
assert_ne!(w, "/bin/bash");
}
#[test]
fn test_should_return_true_if_regex_match() {
let w = Whitelist(vec![r".*?_allow$".into()]);
assert_eq!(w, "/usr/bin/bash_allow");
}
#[test]
fn test_should_return_false_if_regex_not_match() {
let w = Whitelist(vec![r".*?_allow$".into()]);
assert_ne!(w, "/usr/bin/bash_not_allowed");
}
}

View file

@ -3,6 +3,7 @@
use std::sync::Mutex;
mod server;
mod sessions;
mod configuration;
pub(self) static SESSIONS : Mutex<Vec<libcommand::Session>> = Mutex::new(Vec::new());

View file

@ -22,6 +22,7 @@ impl Unix for DaemonServer {
super::SESSIONS.lock().unwrap().push(session);
Ok(Response::new(AuthorizeResponse {
command_arg: request.get_ref().command_arg.clone(),
session_id
}))
}

View file

@ -11,20 +11,18 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let arg = std::env::args()
.skip(1)
.last().unwrap();
let command_arg : libcommand::Command = serde_json::from_str::<libcommand::Command>(&arg)
.unwrap();
let mut client = client::connect().await?;
let request = tonic::Request::new(AuthorizeRequest {
identifier: command_arg.identifier.clone(),
token: command_arg.token.clone(),
command: command_arg.command.clone(),
command_arg: arg,
pid: std::process::id()
});
let response : Response<AuthorizeResponse> = client.authorize(request).await?;
let command_arg = libcommand::Command::from(response.get_ref().command_arg.as_ref());
let mut command : std::process::Command = command_arg.into();
let mut child = command.spawn().unwrap();
child.wait().unwrap();