dnapi-rs - make EnrollMeta cloneable
tfclient - finish enrollment routine
This commit is contained in:
parent
a77e126319
commit
bd76d760f4
|
@ -622,7 +622,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "dnapi-rs"
|
||||
version = "0.1.4"
|
||||
version = "0.1.5"
|
||||
dependencies = [
|
||||
"base64 0.21.0",
|
||||
"base64-serde",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "dnapi-rs"
|
||||
version = "0.1.4"
|
||||
version = "0.1.5"
|
||||
edition = "2021"
|
||||
description = "A rust client for the Defined Networking API"
|
||||
license = "AGPL-3.0-or-later"
|
||||
|
@ -21,9 +21,4 @@ base64 = "0.21.0"
|
|||
serde_json = "1.0.95"
|
||||
trifid-pki = { version = "0.1.6", path = "../trifid-pki", features = ["serde_derive"] }
|
||||
rand = "0.8.5"
|
||||
chrono = "0.4.24"
|
||||
|
||||
[features]
|
||||
default = ["blocking"]
|
||||
blocking = ["reqwest/blocking"]
|
||||
async = []
|
||||
chrono = "0.4.24"
|
|
@ -24,7 +24,7 @@ pub struct Client {
|
|||
server_url: Url
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
/// A struct containing organization metadata returned as a result of enrollment
|
||||
pub struct EnrollMeta {
|
||||
/// The server organization ID this node is now a member of
|
||||
|
|
|
@ -24,7 +24,7 @@ pub struct Client {
|
|||
server_url: Url
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
/// A struct containing organization metadata returned as a result of enrollment
|
||||
pub struct EnrollMeta {
|
||||
/// The server organization ID this node is now a member of
|
||||
|
|
|
@ -15,18 +15,10 @@
|
|||
#![allow(clippy::too_many_lines)]
|
||||
#![allow(clippy::module_name_repetitions)]
|
||||
|
||||
#[cfg(all(feature = "blocking", feature = "async"))]
|
||||
compile_error!("Cannot compile with both blocking and async features at the same time. Please pick one or the other.");
|
||||
|
||||
pub mod message;
|
||||
|
||||
#[cfg(feature = "blocking")]
|
||||
#[path = "client_blocking.rs"]
|
||||
pub mod client;
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
#[path = "client_async.rs"]
|
||||
pub mod client;
|
||||
pub mod client_blocking;
|
||||
pub mod client_async;
|
||||
|
||||
pub mod credentials;
|
||||
pub mod crypto;
|
|
@ -24,7 +24,7 @@ base64 = "0.21.0"
|
|||
chrono = "0.4.24"
|
||||
ipnet = "2.7.1"
|
||||
base64-serde = "0.7.0"
|
||||
dnapi-rs = { version = "0.1.2", path = "../dnapi-rs" }
|
||||
dnapi-rs = { version = "0.1.5", path = "../dnapi-rs" }
|
||||
|
||||
[build-dependencies]
|
||||
serde = { version = "1.0.157", features = ["derive"] }
|
||||
|
|
|
@ -1,14 +1,17 @@
|
|||
use std::fs;
|
||||
use std::sync::mpsc::{Receiver, TryRecvError};
|
||||
use base64::Engine;
|
||||
use chrono::Local;
|
||||
use log::{error, info, warn};
|
||||
use url::Url;
|
||||
use dnapi_rs::client_blocking::Client;
|
||||
use trifid_pki::cert::{serialize_ed25519_public, serialize_x25519_public};
|
||||
use trifid_pki::ed25519_dalek::{SecretKey, SigningKey};
|
||||
use trifid_pki::rand_core::OsRng;
|
||||
use trifid_pki::x25519_dalek::StaticSecret;
|
||||
use crate::config::{load_cdata, save_cdata, TFClientConfig};
|
||||
use crate::daemon::ThreadMessageSender;
|
||||
use crate::dirs::get_nebulaconfig_file;
|
||||
|
||||
pub enum APIWorkerMessage {
|
||||
Shutdown,
|
||||
|
@ -19,6 +22,8 @@ pub enum APIWorkerMessage {
|
|||
pub fn apiworker_main(config: TFClientConfig, instance: String, url: String, _transmitters: ThreadMessageSender, rx: Receiver<APIWorkerMessage>) {
|
||||
let server = Url::parse(&url).unwrap();
|
||||
|
||||
let client = Client::new(format!("tfclient/{}", env!("CARGO_PKG_VERSION")), server).unwrap();
|
||||
|
||||
loop {
|
||||
match rx.try_recv() {
|
||||
Ok(msg) => {
|
||||
|
@ -37,7 +42,7 @@ pub fn apiworker_main(config: TFClientConfig, instance: String, url: String, _tr
|
|||
return;
|
||||
}
|
||||
};
|
||||
if cdata.host_id.is_none() {
|
||||
if cdata.creds.is_none() {
|
||||
info!("not enrolled, cannot perform config update");
|
||||
continue;
|
||||
}
|
||||
|
@ -53,63 +58,30 @@ pub fn apiworker_main(config: TFClientConfig, instance: String, url: String, _tr
|
|||
return;
|
||||
}
|
||||
};
|
||||
if cdata. {
|
||||
if cdata.creds.is_some() {
|
||||
warn!("enrollment failed: already enrolled");
|
||||
continue;
|
||||
}
|
||||
let dh_encoded = base64::engine::general_purpose::STANDARD.encode(serialize_x25519_public(&dh_key.to_bytes()));
|
||||
let ed_encoded = base64::engine::general_purpose::STANDARD.encode(serialize_ed25519_public(&ed_key.to_bytes()));
|
||||
let req = EnrollRequest {
|
||||
code,
|
||||
dh_pubkey: dh_encoded,
|
||||
ed_pubkey: ed_encoded,
|
||||
timestamp: Local::now().format("%Y-%m-%dT%H:%M:%S.%f%:z").to_string(),
|
||||
};
|
||||
let res = match enroll(&server, &req) {
|
||||
Ok(res) => res,
|
||||
Err(e) => {
|
||||
error!("error in api worker thread: {}", e);
|
||||
error!("APIWorker exiting with error");
|
||||
return;
|
||||
}
|
||||
};
|
||||
let resp = match res {
|
||||
APIResponse::Error(e) => {
|
||||
error!("error with enrollment: {}: {}", e.errors[0].code, e.errors[0].message);
|
||||
continue;
|
||||
}
|
||||
APIResponse::Success(resp) => resp
|
||||
};
|
||||
|
||||
info!("Enrolled with server. Host-ID {} config count {}", resp.data.host_id, resp.data.counter);
|
||||
info!("KeyPool {}, org {} {}", resp.data.trusted_keys, resp.data.organization.name, resp.data.organization.id);
|
||||
info!("Config: {}", resp.data.config);
|
||||
|
||||
// Decode the CAPool and config
|
||||
let key_pool_pem = match base64::engine::general_purpose::STANDARD.decode(resp.data.trusted_keys) {
|
||||
Ok(p) => p,
|
||||
let (config, dh_privkey, creds, meta) = match client.enroll(&code) {
|
||||
Ok(resp) => resp,
|
||||
Err(e) => {
|
||||
error!("error with enrollment: {}", e);
|
||||
error!("error with enrollment request: {}", e);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
let config = match base64::engine::general_purpose::STANDARD.decode(resp.data.config) {
|
||||
Ok(p) => p,
|
||||
match fs::write(get_nebulaconfig_file(&instance).expect("Unable to determine nebula config file location"), config) {
|
||||
Ok(_) => (),
|
||||
Err(e) => {
|
||||
error!("error with enrollment: {}", e);
|
||||
error!("unable to save nebula config: {}", e);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let config_str = String::from_utf8(config).unwrap();
|
||||
}
|
||||
|
||||
|
||||
cdata.host_id = Some(resp.data.host_id);
|
||||
cdata.counter = resp.data.counter as i32;
|
||||
cdata.key_pool = Some(String::from_utf8(key_pool_pem).unwrap());
|
||||
cdata.org_name = Some(resp.data.organization.name);
|
||||
cdata.org_id = Some(resp.data.organization.id);
|
||||
cdata.config = Some(config_str);
|
||||
cdata.creds = Some(creds);
|
||||
cdata.dh_privkey = Some(dh_privkey.try_into().expect("32 != 32"));
|
||||
cdata.meta = Some(meta);
|
||||
|
||||
// Save vardata
|
||||
match save_cdata(&instance, cdata) {
|
||||
|
@ -120,6 +92,8 @@ pub fn apiworker_main(config: TFClientConfig, instance: String, url: String, _tr
|
|||
return;
|
||||
}
|
||||
}
|
||||
|
||||
info!("Configuration updated. Sending signal to Nebula worker thread");
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -5,6 +5,7 @@ use std::fs;
|
|||
|
||||
use log::{debug, info};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use dnapi_rs::client_blocking::EnrollMeta;
|
||||
use dnapi_rs::credentials::Credentials;
|
||||
|
||||
use crate::dirs::{get_cdata_dir, get_cdata_file, get_config_dir, get_config_file};
|
||||
|
@ -21,7 +22,8 @@ pub struct TFClientConfig {
|
|||
#[derive(Serialize, Deserialize, Clone)]
|
||||
pub struct TFClientData {
|
||||
pub dh_privkey: Option<[u8; 32]>,
|
||||
pub creds: Option<Credentials>
|
||||
pub creds: Option<Credentials>,
|
||||
pub meta: Option<EnrollMeta>
|
||||
}
|
||||
|
||||
pub fn create_config(instance: &str) -> Result<(), Box<dyn Error>> {
|
||||
|
@ -56,7 +58,7 @@ pub fn create_cdata(instance: &str) -> Result<(), Box<dyn Error>> {
|
|||
info!("Creating data directory...");
|
||||
fs::create_dir_all(get_cdata_dir(instance).ok_or("Unable to load data dir")?)?;
|
||||
info!("Copying default data file to config directory...");
|
||||
let config = TFClientData { host_id: None, ed_privkey: None, dh_privkey: None, counter: 0, key_pool: None, org_id: None, org_name: None, config: None };
|
||||
let config = TFClientData { dh_privkey: None, creds: None, meta: None };
|
||||
let config_str = toml::to_string(&config)?;
|
||||
fs::write(get_cdata_file(instance).ok_or("Unable to load data dir")?, config_str)?;
|
||||
Ok(())
|
||||
|
|
|
@ -18,4 +18,8 @@ pub fn get_cdata_dir(instance: &str) -> Option<PathBuf> {
|
|||
|
||||
pub fn get_cdata_file(instance: &str) -> Option<PathBuf> {
|
||||
get_cdata_dir(instance).map(|f| f.join("tfclient.toml"))
|
||||
}
|
||||
|
||||
pub fn get_nebulaconfig_file(instance: &str) -> Option<PathBuf> {
|
||||
get_cdata_dir(instance).map(|f| f.join("nebula.sk_embedded.yml"))
|
||||
}
|
|
@ -6,7 +6,8 @@ use crate::config::TFClientConfig;
|
|||
use crate::daemon::ThreadMessageSender;
|
||||
|
||||
pub enum NebulaWorkerMessage {
|
||||
Shutdown
|
||||
Shutdown,
|
||||
ConfigUpdated
|
||||
}
|
||||
|
||||
pub fn nebulaworker_main(_config: TFClientConfig, _transmitter: ThreadMessageSender, rx: Receiver<NebulaWorkerMessage>) {
|
||||
|
@ -17,6 +18,9 @@ pub fn nebulaworker_main(_config: TFClientConfig, _transmitter: ThreadMessageSen
|
|||
NebulaWorkerMessage::Shutdown => {
|
||||
info!("recv on command socket: shutdown, stopping");
|
||||
break;
|
||||
},
|
||||
NebulaWorkerMessage::ConfigUpdated => {
|
||||
info!("our configuration has been updated - reloading");
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -232,8 +232,8 @@ fn senthello_handle(client: &mut Client, transmitter: &ThreadMessageSender, comm
|
|||
}
|
||||
};
|
||||
client.stream.write_all(&ctob(JsonMessage::HostID {
|
||||
has_id: data.host_id.is_some(),
|
||||
id: data.host_id
|
||||
has_id: data.creds.is_some(),
|
||||
id: data.creds.map(|c| c.host_id)
|
||||
}))?;
|
||||
},
|
||||
|
||||
|
|
Loading…
Reference in New Issue