Commit fd7b2630 authored by Szymon Zimnowoda's avatar Szymon Zimnowoda
Browse files

get plugin_auth key from the env

parent f337f230
Showing with 56 additions and 16 deletions
+56 -16
......@@ -19,5 +19,6 @@ exec target/debug/pod \
--port 3030 \
--opened-connections 4 \
--owner-key-for-example-data="c382725f6a1f427788e75c57137574c84edc143ff92a4a85979c2f68134faaeb" \
--db-key-for-example-data="840bcff6b8f2486fb00a9e8728214777fcd598f1592e452fa985de1fb5a40ce9"
--db-key-for-example-data="840bcff6b8f2486fb00a9e8728214777fcd598f1592e452fa985de1fb5a40ce9" \
--plugin-auth-key="840bcff6b8f2486fb00a9e8728214777fcd598f1592e452fa985de1fb5a40ce9"
"$@"
......@@ -203,6 +203,10 @@ pub struct CliOptions {
)]
pub owner_key_for_example_data: Option<String>,
/// Key used in encrypting PluginAuth data
#[arg(long, env = "POD_PLUGIN_AUTH_KEY")]
pub plugin_auth_key: Secret<String>,
/// DB credentials containing example data
#[arg(
long,
......@@ -285,6 +289,7 @@ pub mod tests {
opened_connections: None,
owner_key_for_example_data: None,
db_key_for_example_data: None,
plugin_auth_key: Secret::new(String::default()),
}
}
}
......@@ -5,15 +5,12 @@
// * situations where impact on mock-ability is really zero,
// and there are clear maintenance/performance benefits of doing so
use std::sync::OnceLock;
use chacha20poly1305::XChaCha20Poly1305;
use lazy_static::lazy_static;
lazy_static! {
/// Global/static Cipher used for PluginAuth.
/// All plugins will be started with database_key (and potentially other keys) encrypted
/// via this Cipher. This cipher is re-initialized randomly upon restart
/// If you want to read more on the usage of this key in Pod,
/// check documentation in HTTP_API.md and Plugins.md.
pub static ref CIPHER: XChaCha20Poly1305 =
crate::plugin_auth_crypto::generate_xchacha20poly1305_cipher();
pub static CIPHER: OnceLock<XChaCha20Poly1305> = OnceLock::new();
pub fn get_plugin_auth_cipher<'a>() -> &'a XChaCha20Poly1305 {
CIPHER.get().expect("PluginAuth cipher is not initialized")
}
......@@ -19,7 +19,11 @@ pub type SHA256Output = GenericArray<u8, typenum::consts::U32>;
pub fn generate_xchacha20poly1305_cipher() -> XChaCha20Poly1305 {
let key: [u8; 32] = rand::random();
let key = Key::from_slice(&key);
generate_xchacha20poly1305_cipher_from_key(&key)
}
pub fn generate_xchacha20poly1305_cipher_from_key(key: &[u8; 32]) -> XChaCha20Poly1305 {
let key = Key::from_slice(key);
XChaCha20Poly1305::new(key)
}
......@@ -28,7 +32,7 @@ pub fn generate_xchacha20poly1305_cipher() -> XChaCha20Poly1305 {
pub fn create_plugin_auth(database_key: &str) -> Result<PluginAuth> {
let nonce: [u8; 24] = rand::random();
let nonce = XNonce::from_slice(&nonce); // MUST be unique
let cipher = &global_static::CIPHER;
let cipher = global_static::get_plugin_auth_cipher();
let database_key: Vec<u8> = hex::decode(database_key)?;
let encrypted = cipher.encrypt(nonce, database_key.as_slice())?;
Ok(PluginAuth {
......@@ -47,7 +51,7 @@ pub fn extract_database_key(plugin_auth: &PluginAuth) -> Result<DatabaseKey> {
let nonce = hex::decode(&plugin_auth.data.nonce)?;
let encrypted_permissions = hex::decode(&plugin_auth.data.encrypted_permissions)?;
let nonce = XNonce::from_slice(&nonce);
let cipher = &global_static::CIPHER;
let cipher = global_static::get_plugin_auth_cipher();
let decrypted = cipher.decrypt(nonce, encrypted_permissions.as_ref())?;
if decrypted.len() != 32 && decrypted.is_empty().not() {
return Err(bad_request! { "Key has incorrect length: {}", decrypted.len() });
......@@ -130,11 +134,17 @@ impl TryFrom<String> for DatabaseKey {
#[cfg(test)]
mod tests {
use crate::global_static::CIPHER;
use super::*;
#[test]
fn test_encrypt_decrypt() {
let db_key = "0".repeat(64);
let raw_key = [0u8; 32];
let _ = CIPHER.set(generate_xchacha20poly1305_cipher_from_key(&raw_key));
let db_key_struct = DatabaseKey::try_from(db_key.clone()).unwrap();
let auth = db_key_struct.create_plugin_auth().unwrap();
assert!(!auth.data.nonce.contains(&db_key));
......
......@@ -6,9 +6,11 @@ use crate::{
database_pool::{get_db_connection, initialize_db, InitDb},
db_model::ItemBase,
error::{ErrorContext, Result},
internal_api,
plugin_auth_crypto::auth_to_database_key,
global_static::CIPHER,
internal_api, internal_error,
plugin_auth_crypto::{auth_to_database_key, generate_xchacha20poly1305_cipher_from_key},
};
use secrecy::ExposeSecret;
use std::ops::Deref;
use tracing::{debug, info, warn};
......@@ -16,6 +18,9 @@ pub async fn initialize(init_db: &InitDb) -> Result<()> {
initialize_database(init_db)
.await
.context_str("While initializing shared database connection")?;
initialize_plugin_auth_cipher().context_str("While initializing PluginAuth cipher")?;
initialize_plugins(init_db)
.await
.context_str("While initializing shared plugins")
......@@ -90,6 +95,25 @@ pub async fn initialize_plugins(init_db: &InitDb) -> Result<()> {
Ok(())
}
fn initialize_plugin_auth_cipher() -> Result<()> {
if PARSED.plugin_auth_key.expose_secret().len() != 64 {
return Err(internal_error!(
"PluginAuth key needs to have exactly 64 hexadecimal characters"
));
}
let mut raw_key = [0u8; 32];
hex::decode_to_slice(PARSED.plugin_auth_key.expose_secret(), &mut raw_key)?;
CIPHER
.set(generate_xchacha20poly1305_cipher_from_key(
secrecy::Secret::from(raw_key).expose_secret(),
))
.map_err(|_e| internal_error!("PluginAuth cipher is already set"))?;
Ok(())
}
async fn clean_db_from_plugins(conn: &mut AsyncConnection) -> Result<()> {
conn.in_write_transaction(|tx: AsyncTx| async move {
let schema = database_api::get_schema(&tx)?;
......
......@@ -58,5 +58,6 @@ pub fn default_cli() -> CliOptions {
opened_connections: None,
owner_key_for_example_data: None,
db_key_for_example_data: None,
plugin_auth_key: Secret::new(String::default()),
}
}
......@@ -251,6 +251,7 @@ impl TestDataBuilder {
format!("--port={pod_port}"),
format!("--owner-key-for-pod={shared_db_owner_key}"),
format!("--db-key-for-pod={shared_db_database_key}"),
format!("--plugin-auth-key={}", "0".repeat(64)),
];
if let Some(shared_plugins_arg) = self.shared_plugins_arg {
......
......@@ -130,6 +130,7 @@ async fn test_pod_keys_works_after_restart(ctx: &mut TestData) {
"--owners=ANY",
"--non-tls",
&format!("--port={}", ctx.pod_port),
&format!("--plugin-auth-key={}", "0".repeat(64)),
])
.await;
......
......@@ -5,7 +5,7 @@ set -euETo pipefail
#### Start Pod
cargo build
target/debug/pod --insecure-non-tls=0.0.0.0 --owners=ANY --port=4956 &
target/debug/pod --insecure-non-tls=0.0.0.0 --owners=ANY --port=4956 --plugin-auth-key="840bcff6b8f2486fb00a9e8728214777fcd598f1592e452fa985de1fb5a40ce9" &
pid=$!
trap 'kill $pid' EXIT
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment