[companion] Introduce subcommands
Subcommands for `generate`-ing keys and `encrypt`-ing secrets. Generated artifacts can be consumed by `coffer-server`. Signed-off-by: Armin Friedl <dev@friedl.net>
This commit is contained in:
parent
b3b86b4238
commit
8427a6ad53
7 changed files with 96 additions and 38 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1,4 +1,4 @@
|
||||||
/target
|
/target
|
||||||
**/*.rs.bk
|
**/*.rs.bk
|
||||||
*.cbor
|
*.cbor
|
||||||
secreq.yaml
|
*.yaml
|
3
Cargo.lock
generated
3
Cargo.lock
generated
|
@ -81,11 +81,14 @@ dependencies = [
|
||||||
name = "coffer-companion"
|
name = "coffer-companion"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde_cbor 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde_cbor 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde_yaml 0.8.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde_yaml 0.8.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"sodiumoxide 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"sodiumoxide 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"structopt 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
6
TODO.org
6
TODO.org
|
@ -1,7 +1,13 @@
|
||||||
* General
|
* General
|
||||||
** TODO Add a license
|
** TODO Add a license
|
||||||
** TODO Better communication protocol
|
** TODO Better communication protocol
|
||||||
|
** TODO Add tests
|
||||||
* Coffer Server
|
* Coffer Server
|
||||||
|
** TODO Add secrets on-the-fly
|
||||||
|
** TODO Store secrets in secure memory
|
||||||
|
- Not persisted
|
||||||
|
- Nulled out
|
||||||
|
- Optional encrypted
|
||||||
* Coffer Client
|
* Coffer Client
|
||||||
** DONE Set environment variables
|
** DONE Set environment variables
|
||||||
CLOSED: [2019-11-27 Wed 22:51]
|
CLOSED: [2019-11-27 Wed 22:51]
|
||||||
|
|
|
@ -9,6 +9,9 @@ edition = "2018"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
# Base tools
|
# Base tools
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
|
env_logger="0.7"
|
||||||
|
structopt = "0.3"
|
||||||
|
quick-error = "1.2"
|
||||||
# Key management/Cryptography
|
# Key management/Cryptography
|
||||||
sodiumoxide = "0.2.5"
|
sodiumoxide = "0.2.5"
|
||||||
# Communication
|
# Communication
|
||||||
|
|
26
coffer-companion/src/encrypt.rs
Normal file
26
coffer-companion/src/encrypt.rs
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
use sodiumoxide::crypto::sealedbox;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::{Write};
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use crate::generate::MasterKey;
|
||||||
|
|
||||||
|
type Secrets = HashMap<String, String>;
|
||||||
|
|
||||||
|
pub fn generate_encrypted_secrets(yaml: PathBuf, out: PathBuf, masterkey: PathBuf) {
|
||||||
|
let reader = File::open(&yaml)
|
||||||
|
.expect(&format!{"Could not read file {}", masterkey.display()});
|
||||||
|
|
||||||
|
let secrets: Secrets = serde_yaml::from_reader(reader)
|
||||||
|
.expect(&format!{"Could not deserialize secrets from {}", &yaml.display()});
|
||||||
|
|
||||||
|
let masterkey: MasterKey = (&masterkey).into();
|
||||||
|
|
||||||
|
let secrets_bin = serde_cbor::to_vec(&secrets).unwrap();
|
||||||
|
let sealed_secrets_bin = sealedbox::seal(&secrets_bin, &masterkey.public_key);
|
||||||
|
|
||||||
|
File::create(&out)
|
||||||
|
.and_then(|mut f| f.write(&sealed_secrets_bin))
|
||||||
|
.expect(&format!{"Could not create out file {}", &out.display()});
|
||||||
|
}
|
33
coffer-companion/src/generate.rs
Normal file
33
coffer-companion/src/generate.rs
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
use sodiumoxide::crypto::box_;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::fs::File;
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
pub struct MasterKey {
|
||||||
|
pub public_key: box_::PublicKey,
|
||||||
|
secret_key: box_::SecretKey,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn generate_key(out: PathBuf) {
|
||||||
|
let keypair = box_::gen_keypair();
|
||||||
|
let masterkey: MasterKey = MasterKey {
|
||||||
|
public_key: keypair.0,
|
||||||
|
secret_key: keypair.1,
|
||||||
|
};
|
||||||
|
|
||||||
|
let writer = File::create(&out)
|
||||||
|
.expect(&format!{"Could not create out file {}", &out.display()});
|
||||||
|
|
||||||
|
serde_cbor::to_writer(writer, &masterkey)
|
||||||
|
.expect(&format!{"Couldn't deserialize to key file {}", &out.display()});
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&PathBuf> for MasterKey {
|
||||||
|
fn from(masterkey: &PathBuf) -> Self {
|
||||||
|
let reader = File::open(masterkey)
|
||||||
|
.expect(&format!{"Could not read file {}", masterkey.display()});
|
||||||
|
|
||||||
|
serde_cbor::from_reader(reader).unwrap()
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,48 +1,35 @@
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use sodiumoxide::crypto::box_;
|
|
||||||
use sodiumoxide::crypto::sealedbox;
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use structopt::StructOpt;
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
mod generate;
|
||||||
struct MasterKey {
|
mod encrypt;
|
||||||
public_key: box_::PublicKey,
|
|
||||||
secret_key: box_::SecretKey,
|
#[derive(StructOpt, Debug)]
|
||||||
|
enum Args {
|
||||||
|
Generate {
|
||||||
|
#[structopt(short, long, parse(from_os_str))]
|
||||||
|
out: PathBuf
|
||||||
|
},
|
||||||
|
Encrypt {
|
||||||
|
#[structopt(short, long, parse(from_os_str))]
|
||||||
|
yaml: PathBuf,
|
||||||
|
#[structopt(short, long, parse(from_os_str))]
|
||||||
|
out: PathBuf,
|
||||||
|
#[structopt(short, long, parse(from_os_str))]
|
||||||
|
masterkey: PathBuf,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ClientKey {
|
|
||||||
id: String,
|
|
||||||
public_key: box_::PublicKey,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type Secrets = HashMap<String, String>;
|
|
||||||
pub type Secs = Vec<String>;
|
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn Error>> {
|
fn main() -> Result<(), Box<dyn Error>> {
|
||||||
let keypair = box_::gen_keypair();
|
let args: Args = Args::from_args();
|
||||||
let masterkey: MasterKey = MasterKey {
|
|
||||||
public_key: keypair.0,
|
|
||||||
secret_key: keypair.1,
|
|
||||||
};
|
|
||||||
|
|
||||||
let f = File::create("./masterkey.cbor")?;
|
match args {
|
||||||
serde_cbor::to_writer(f, &masterkey)?;
|
Args::Generate {out} => generate::generate_key(out),
|
||||||
|
Args::Encrypt {yaml, out, masterkey} => encrypt::generate_encrypted_secrets(yaml, out, masterkey)
|
||||||
let secrets: Secrets = [
|
}
|
||||||
("ABC".to_owned(), "DEF".to_owned()),
|
|
||||||
("XYZ".to_owned(), "ABC".to_owned()),
|
|
||||||
]
|
|
||||||
.iter()
|
|
||||||
.cloned()
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let sc_res = serde_cbor::to_vec(&secrets)?;
|
|
||||||
let sc_res = sealedbox::seal(&sc_res, &masterkey.public_key);
|
|
||||||
let mut f = File::create("./secrets.cbor")?;
|
|
||||||
f.write(&sc_res)?;
|
|
||||||
f.flush()?;
|
|
||||||
|
|
||||||
let secreta = "ABC".to_owned();
|
let secreta = "ABC".to_owned();
|
||||||
let mut f = File::create("./keyreq_a.cbor")?;
|
let mut f = File::create("./keyreq_a.cbor")?;
|
||||||
|
|
Loading…
Reference in a new issue