Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion approve_or_deny.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
# We expect to receive: <zone name> <zone serial> <approval token>
set -euo pipefail -x

Expand Down
2 changes: 1 addition & 1 deletion approve_or_deny_signed.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
# We expect to receive: <zone name> <zone serial> <approval token>
set -euo pipefail -x

Expand Down
12 changes: 9 additions & 3 deletions src/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use arc_swap::ArcSwap;
use log::{debug, info};
use std::collections::HashMap;
use std::fmt::Display;
use std::path::PathBuf;
use std::str::FromStr;
use std::sync::Arc;
use tokio::sync::mpsc::{self, Receiver, Sender};
Expand Down Expand Up @@ -261,6 +262,11 @@ impl Manager {
let tsig_key = std::env::var("ZL_TSIG_KEY")
.unwrap_or("hmac-sha256:zlCZbVJPIhobIs1gJNQfrsS3xCxxsR9pMUrGwG8OgG8=".into());

// Global settings for dnst keyset
// TODO: Should probably be configurable
let dnst_keyset_bin_path: PathBuf = "dnst".into();
let dnst_keyset_data_dir: PathBuf = "/tmp/keyset/".into();

self.spawn_unit(
"ZL",
Unit::ZoneLoader(ZoneLoader {
Expand Down Expand Up @@ -291,16 +297,15 @@ impl Manager {
self.spawn_unit(
"KM",
Unit::KeyManager(KeyManagerUnit {
dnst_keyset_bin_path: "/tmp/dnst".into(),
dnst_keyset_data_dir: "/tmp".into(),
dnst_keyset_bin_path,
dnst_keyset_data_dir: dnst_keyset_data_dir.clone(),
update_tx: update_tx.clone(),
}),
);

self.spawn_unit(
"ZS",
Unit::ZoneSigner(ZoneSignerUnit {
keys_path: "/tmp/keys".into(),
treat_single_keys_as_csks: true,
max_concurrent_operations: 1,
max_concurrent_rrsig_generation_tasks: 32,
Expand All @@ -310,6 +315,7 @@ impl Manager {
rrsig_expiration_offset_secs: 60 * 60 * 24 * 14,
kmip_server_conn_settings,
update_tx: update_tx.clone(),
dnst_keyset_data_dir,
}),
);

Expand Down
70 changes: 55 additions & 15 deletions src/units/key_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ use crate::comms::{ApplicationCommand, GraphStatus, Terminated};
use crate::manager::Component;
use crate::metrics;
use crate::payload::Update;
use bytes::Bytes;
use core::fmt::Display;
use core::time::Duration;
use domain::base::Name;
use domain::dnssec::sign::keys::keyset::{KeySet, UnixTime};
use domain::zonetree::Zone;
use log::{error, info};
Expand Down Expand Up @@ -86,20 +88,65 @@ impl KeyManager {
self.tick().await;
}
cmd = cmd_rx.recv() => {
if let Some(ApplicationCommand::Terminate) = cmd {
return Err(Terminated);
}
self.run_cmd(cmd)?;
}
}
}
}

fn run_cmd(&self, cmd: Option<ApplicationCommand>) -> Result<(), Terminated> {
match cmd {
Some(ApplicationCommand::Terminate) | None => Err(Terminated),
Some(ApplicationCommand::RegisterZone {
register: crate::api::ZoneAdd { name, .. },
}) => {
let state_path = self.dnst_keyset_data_dir.join(format!("{name}.state"));

let status = self
.keyset_cmd(&name)
.arg("create")
.arg("-n")
.arg(name.to_string())
.arg("-s")
.arg(&state_path)
.status();

if status.is_err() {
error!("[ZL]: Error creating keyset");
return Err(Terminated);
}

// TODO: This should not happen immediately after
// `keyset create` but only once the zone is enabled.
// We currently do not have a good mechanism for that
// so we init the key immediately.
let status = self.keyset_cmd(&name).arg("init").status();

if status.is_err() {
error!("[ZL]: Error initializing keyset");
return Err(Terminated);
}

Ok(())
}
Some(_) => Ok(()), // not for us
}
}

/// Create a keyset command with the config file for the given zone
fn keyset_cmd(&self, name: impl Display) -> Command {
let cfg_path = self.dnst_keyset_data_dir.join(format!("{name}.cfg"));
let mut cmd = Command::new(&self.dnst_keyset_bin_path);
cmd.arg("keyset").arg("-c").arg(&cfg_path);
cmd
}

async fn tick(&self) {
let zone_tree = self.component.unsigned_zones();
let mut ks_info = self.ks_info.lock().await;
for zone in zone_tree.load().iter_zones() {
let apex_name = zone.apex_name().to_string();
let state_path = Path::new("/tmp/").join(format!("{apex_name}.state"));
let state_path = self.dnst_keyset_data_dir.join(format!("{apex_name}.state"));
if !state_path.exists() {
continue;
}
Expand Down Expand Up @@ -130,16 +177,8 @@ impl KeyManager {
};

if *cron_next < UnixTime::now() {
// Run cron
let cfg_path = self.dnst_keyset_data_dir.join(format!("{apex_name}.cfg"));
let mut args = vec!["keyset", "-c"];
args.push(cfg_path.to_str().unwrap());
args.push("cron");
println!(
"Invoking keyset cron for zone {apex_name} with {}",
args.join(" ")
);
let Ok(res) = Command::new(&self.dnst_keyset_bin_path).args(args).output() else {
println!("Invoking keyset cron for zone {apex_name}");
let Ok(res) = self.keyset_cmd(&apex_name).arg("cron").output() else {
error!(
"Failed to invoke keyset binary at '{}",
self.dnst_keyset_bin_path.display()
Expand Down Expand Up @@ -186,7 +225,8 @@ impl KeyManager {
};
if new_info.retries >= CRON_MAX_RETRIES {
error!(
"The command 'dnst keyset cron' for config {} failed to update state file {}", cfg_path.display(), state_path.display()
"The command 'dnst keyset cron' failed to update state file {}",
state_path.display()
);

// Clear cron_next.
Expand Down
14 changes: 7 additions & 7 deletions src/units/zone_signer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,6 @@ use core::sync::atomic::AtomicBool;

#[derive(Debug)]
pub struct ZoneSignerUnit {
pub keys_path: PathBuf,

pub rrsig_inception_offset_secs: u32,

pub rrsig_expiration_offset_secs: u32,
Expand All @@ -135,6 +133,8 @@ pub struct ZoneSignerUnit {
pub kmip_server_conn_settings: HashMap<String, KmipServerConnectionSettings>,

pub update_tx: mpsc::UnboundedSender<Update>,

pub dnst_keyset_data_dir: PathBuf,
}

#[allow(dead_code)]
Expand Down Expand Up @@ -226,8 +226,8 @@ impl ZoneSignerUnit {
self.max_concurrent_rrsig_generation_tasks,
self.treat_single_keys_as_csks,
self.update_tx,
self.keys_path,
kmip_servers,
self.dnst_keyset_data_dir,
)
.run(cmd_rx)
.await?;
Expand Down Expand Up @@ -292,8 +292,8 @@ struct ZoneSigner {
signer_status: Arc<RwLock<ZoneSignerStatus>>,
treat_single_keys_as_csks: bool,
update_tx: mpsc::UnboundedSender<Update>,
_keys_path: PathBuf,
kmip_servers: HashMap<String, SyncConnPool>,
dnst_keyset_data_dir: PathBuf,
}

impl ZoneSigner {
Expand All @@ -308,8 +308,8 @@ impl ZoneSigner {
max_concurrent_rrsig_generation_tasks: usize,
treat_single_keys_as_csks: bool,
update_tx: mpsc::UnboundedSender<Update>,
keys_path: PathBuf,
kmip_servers: HashMap<String, SyncConnPool>,
dnst_keyset_data_dir: PathBuf,
) -> Self {
Self {
component,
Expand All @@ -322,8 +322,8 @@ impl ZoneSigner {
signer_status: Default::default(),
treat_single_keys_as_csks,
update_tx,
_keys_path: keys_path,
kmip_servers,
dnst_keyset_data_dir,
}
}

Expand Down Expand Up @@ -446,7 +446,7 @@ impl ZoneSigner {
trace!("Reading dnst keyset DNSKEY RRs and RRSIG RRs");
// Read the DNSKEY RRs and DNSKEY RRSIG RR from the keyset state.
let apex_name = zone.apex_name().to_string();
let state_path = Path::new("/tmp/").join(format!("{apex_name}.state"));
let state_path = self.dnst_keyset_data_dir.join(format!("{apex_name}.state"));
let state = std::fs::read_to_string(&state_path).map_err(|err| format!("Unable to read `dnst keyset` state file '{}' while signing zone {zone_name}: {err}", state_path.display()))?;
let state: KeySetState = serde_json::from_str(&state).unwrap();
for dnskey_rr in state.dnskey_rrset {
Expand Down
Loading