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.
|
# It is not intended for manual editing.
|
||||||
version = 3
|
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]]
|
[[package]]
|
||||||
name = "anyhow"
|
name = "anyhow"
|
||||||
version = "1.0.68"
|
version = "1.0.68"
|
||||||
|
@ -121,8 +130,10 @@ name = "command_gateway"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"prost",
|
"prost",
|
||||||
|
"regex",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
"serde_yaml",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-stream",
|
"tokio-stream",
|
||||||
"tonic",
|
"tonic",
|
||||||
|
@ -613,6 +624,8 @@ version = "1.7.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733"
|
checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"aho-corasick",
|
||||||
|
"memchr",
|
||||||
"regex-syntax",
|
"regex-syntax",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -674,6 +687,19 @@ dependencies = [
|
||||||
"serde",
|
"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]]
|
[[package]]
|
||||||
name = "slab"
|
name = "slab"
|
||||||
version = "0.4.7"
|
version = "0.4.7"
|
||||||
|
@ -939,6 +965,12 @@ version = "1.0.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc"
|
checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unsafe-libyaml"
|
||||||
|
version = "0.2.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bc7ed8ba44ca06be78ea1ad2c3682a43349126c8818054231ee6f4748012aed2"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uuid"
|
name = "uuid"
|
||||||
version = "1.2.2"
|
version = "1.2.2"
|
||||||
|
|
|
@ -21,6 +21,8 @@ path = "src/interpreter/main.rs"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
|
serde_yaml = "0.9"
|
||||||
|
regex = "1.7"
|
||||||
uuid = { version = "1.2.2", features = [
|
uuid = { version = "1.2.2", features = [
|
||||||
"v4", # Lets you generate random UUIDs
|
"v4", # Lets you generate random UUIDs
|
||||||
"fast-rng", # Use a faster (but still sufficiently random) RNG
|
"fast-rng", # Use a faster (but still sufficiently random) RNG
|
||||||
|
|
|
@ -10,18 +10,16 @@ service Unix {
|
||||||
}
|
}
|
||||||
|
|
||||||
message AuthorizeRequest {
|
message AuthorizeRequest {
|
||||||
// identifier of the project
|
// json like argument
|
||||||
string identifier = 1;
|
string command_arg = 1;
|
||||||
// ssh_keys from ssh agent
|
|
||||||
string token = 2;
|
|
||||||
// command like /bin/bash
|
|
||||||
string command = 3;
|
|
||||||
// pid
|
// pid
|
||||||
uint32 pid = 4;
|
uint32 pid = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message AuthorizeResponse {
|
message AuthorizeResponse {
|
||||||
string session_id = 2;
|
string session_id = 1;
|
||||||
|
// json like arguments changed by daemon
|
||||||
|
string command_arg = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message TerminateRequest {
|
message TerminateRequest {
|
||||||
|
|
|
@ -3,11 +3,10 @@ use serde::{Serialize, Deserialize};
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
pub struct Command {
|
pub struct Command {
|
||||||
pub identifier: String,
|
|
||||||
pub token: String,
|
|
||||||
pub command: String,
|
pub command: String,
|
||||||
pub envs: HashMap<String, 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 {
|
impl Into<std::process::Command> for Command {
|
||||||
|
@ -19,4 +18,21 @@ impl Into<std::process::Command> for Command {
|
||||||
command.envs(self.envs);
|
command.envs(self.envs);
|
||||||
command
|
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;
|
use std::sync::Mutex;
|
||||||
mod server;
|
mod server;
|
||||||
mod sessions;
|
mod sessions;
|
||||||
|
mod configuration;
|
||||||
|
|
||||||
pub(self) static SESSIONS : Mutex<Vec<libcommand::Session>> = Mutex::new(Vec::new());
|
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);
|
super::SESSIONS.lock().unwrap().push(session);
|
||||||
|
|
||||||
Ok(Response::new(AuthorizeResponse {
|
Ok(Response::new(AuthorizeResponse {
|
||||||
|
command_arg: request.get_ref().command_arg.clone(),
|
||||||
session_id
|
session_id
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,20 +11,18 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let arg = std::env::args()
|
let arg = std::env::args()
|
||||||
.skip(1)
|
.skip(1)
|
||||||
.last().unwrap();
|
.last().unwrap();
|
||||||
let command_arg : libcommand::Command = serde_json::from_str::<libcommand::Command>(&arg)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let mut client = client::connect().await?;
|
let mut client = client::connect().await?;
|
||||||
|
|
||||||
let request = tonic::Request::new(AuthorizeRequest {
|
let request = tonic::Request::new(AuthorizeRequest {
|
||||||
identifier: command_arg.identifier.clone(),
|
command_arg: arg,
|
||||||
token: command_arg.token.clone(),
|
|
||||||
command: command_arg.command.clone(),
|
|
||||||
pid: std::process::id()
|
pid: std::process::id()
|
||||||
});
|
});
|
||||||
|
|
||||||
let response : Response<AuthorizeResponse> = client.authorize(request).await?;
|
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 command : std::process::Command = command_arg.into();
|
||||||
let mut child = command.spawn().unwrap();
|
let mut child = command.spawn().unwrap();
|
||||||
child.wait().unwrap();
|
child.wait().unwrap();
|
||||||
|
|
Reference in a new issue