[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:
Armin Friedl 2019-11-28 23:49:19 +01:00
parent b3b86b4238
commit 8427a6ad53
Signed by: armin
GPG key ID: 48C726EEE7FBCBC8
7 changed files with 96 additions and 38 deletions

2
.gitignore vendored
View file

@ -1,4 +1,4 @@
/target
**/*.rs.bk
*.cbor
secreq.yaml
*.yaml

3
Cargo.lock generated
View file

@ -81,11 +81,14 @@ dependencies = [
name = "coffer-companion"
version = "0.2.0"
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)",
"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_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)",
"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]]

View file

@ -1,7 +1,13 @@
* General
** TODO Add a license
** TODO Better communication protocol
** TODO Add tests
* Coffer Server
** TODO Add secrets on-the-fly
** TODO Store secrets in secure memory
- Not persisted
- Nulled out
- Optional encrypted
* Coffer Client
** DONE Set environment variables
CLOSED: [2019-11-27 Wed 22:51]

View file

@ -9,6 +9,9 @@ edition = "2018"
[dependencies]
# Base tools
log = "0.4"
env_logger="0.7"
structopt = "0.3"
quick-error = "1.2"
# Key management/Cryptography
sodiumoxide = "0.2.5"
# Communication

View 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()});
}

View 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()
}
}

View file

@ -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::fs::File;
use std::io::Write;
use std::path::PathBuf;
use structopt::StructOpt;
#[derive(Debug, Serialize, Deserialize)]
struct MasterKey {
public_key: box_::PublicKey,
secret_key: box_::SecretKey,
mod generate;
mod encrypt;
#[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>> {
let keypair = box_::gen_keypair();
let masterkey: MasterKey = MasterKey {
public_key: keypair.0,
secret_key: keypair.1,
};
let args: Args = Args::from_args();
let f = File::create("./masterkey.cbor")?;
serde_cbor::to_writer(f, &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()?;
match args {
Args::Generate {out} => generate::generate_key(out),
Args::Encrypt {yaml, out, masterkey} => encrypt::generate_encrypted_secrets(yaml, out, masterkey)
}
let secreta = "ABC".to_owned();
let mut f = File::create("./keyreq_a.cbor")?;