Add metadata in command, add whitelist, add daemon config
This commit is contained in:
parent
482dd830dc
commit
46d401493b
9 changed files with 123 additions and 16 deletions
32
Cargo.lock
generated
32
Cargo.lock
generated
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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(),
|
||||
}
|
||||
}
|
||||
}
|
14
src/daemon/configuration/mod.rs
Normal file
14
src/daemon/configuration/mod.rs
Normal 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
|
||||
}
|
||||
}
|
45
src/daemon/configuration/whitelist.rs
Normal file
45
src/daemon/configuration/whitelist.rs
Normal 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");
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
|
||||
|
|
|
@ -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
|
||||
}))
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
Reference in a new issue