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
13 changes: 6 additions & 7 deletions src/commands/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ use crate::cli::prompt::Prompt;
use crate::commands::init::{PATH_CA_TRUST, SECRET_ID_TTL, TOKEN_TTL};
use crate::i18n::Messages;
use crate::state::{AppEntry, AppRoleEntry, DeployType, StateFile};

const STATE_FILE_NAME: &str = "state.json";
const APPROLE_PREFIX: &str = "bootroot-app-";
const APP_KV_BASE: &str = "bootroot/apps";
const APP_SECRET_DIR: &str = "apps";
Expand All @@ -23,12 +21,12 @@ const APP_SECRET_ID_FILENAME: &str = "secret_id";
const CA_TRUST_KEY: &str = "trusted_ca_sha256";

pub(crate) async fn run_app_add(args: &AppAddArgs, messages: &Messages) -> Result<()> {
let state_path = Path::new(STATE_FILE_NAME);
let state_path = StateFile::default_path();
if !state_path.exists() {
anyhow::bail!(messages.error_state_missing());
}
let mut state =
StateFile::load(state_path).with_context(|| messages.error_parse_state_failed())?;
StateFile::load(&state_path).with_context(|| messages.error_parse_state_failed())?;

let resolved = resolve_app_add_args(args, messages)?;
if state.apps.contains_key(&resolved.service_name) {
Expand Down Expand Up @@ -106,7 +104,7 @@ pub(crate) async fn run_app_add(args: &AppAddArgs, messages: &Messages) -> Resul
.apps
.insert(resolved.service_name.clone(), entry.clone());
state
.save(state_path)
.save(&state_path)
.with_context(|| messages.error_serialize_state_failed())?;

print_app_add_summary(
Expand All @@ -119,11 +117,12 @@ pub(crate) async fn run_app_add(args: &AppAddArgs, messages: &Messages) -> Resul
}

pub(crate) fn run_app_info(args: &AppInfoArgs, messages: &Messages) -> Result<()> {
let state_path = Path::new(STATE_FILE_NAME);
let state_path = StateFile::default_path();
if !state_path.exists() {
anyhow::bail!(messages.error_state_missing());
}
let state = StateFile::load(state_path).with_context(|| messages.error_parse_state_failed())?;
let state =
StateFile::load(&state_path).with_context(|| messages.error_parse_state_failed())?;
let entry = state
.apps
.get(&args.service_name)
Expand Down
59 changes: 59 additions & 0 deletions src/commands/init/constants.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
pub(crate) const DEFAULT_OPENBAO_URL: &str = "http://localhost:8200";
pub(crate) const DEFAULT_KV_MOUNT: &str = "secret";
pub(crate) const DEFAULT_SECRETS_DIR: &str = "secrets";
pub(crate) const DEFAULT_COMPOSE_FILE: &str = "docker-compose.yml";
pub(crate) const DEFAULT_STEPCA_URL: &str = "https://localhost:9000";
pub(crate) const DEFAULT_STEPCA_PROVISIONER: &str = "acme";

pub(crate) const DEFAULT_CA_NAME: &str = "Bootroot CA";
pub(crate) const DEFAULT_CA_PROVISIONER: &str = "admin";
pub(crate) const DEFAULT_CA_DNS: &str = "localhost,bootroot-ca";
pub(crate) const DEFAULT_CA_ADDRESS: &str = ":9000";
pub(crate) const SECRET_BYTES: usize = 32;
pub(crate) const DEFAULT_RESPONDER_TOKEN_TTL_SECS: u64 = 60;
pub(crate) const DEFAULT_RESPONDER_ADMIN_URL: &str = "http://bootroot-http01:8080";
pub(crate) const RESPONDER_TEMPLATE_DIR: &str = "templates";
pub(crate) const RESPONDER_TEMPLATE_NAME: &str = "responder.toml.ctmpl";
pub(crate) const RESPONDER_CONFIG_DIR: &str = "responder";
pub(crate) const RESPONDER_CONFIG_NAME: &str = "responder.toml";
pub(crate) const RESPONDER_COMPOSE_OVERRIDE_NAME: &str = "docker-compose.responder.override.yml";
pub(crate) const STEPCA_PASSWORD_TEMPLATE_NAME: &str = "password.txt.ctmpl";
pub(crate) const STEPCA_CA_JSON_TEMPLATE_NAME: &str = "ca.json.ctmpl";
pub(crate) const OPENBAO_AGENT_DIR: &str = "openbao";
pub(crate) const OPENBAO_AGENT_STEPCA_DIR: &str = "stepca";
pub(crate) const OPENBAO_AGENT_RESPONDER_DIR: &str = "responder";
pub(crate) const OPENBAO_AGENT_CONFIG_NAME: &str = "agent.hcl";
pub(crate) const OPENBAO_AGENT_ROLE_ID_NAME: &str = "role_id";
pub(crate) const OPENBAO_AGENT_SECRET_ID_NAME: &str = "secret_id";
pub(crate) const OPENBAO_AGENT_COMPOSE_OVERRIDE_NAME: &str =
"docker-compose.openbao-agent.override.yml";
pub(crate) const OPENBAO_AGENT_STEPCA_SERVICE: &str = "openbao-agent-stepca";
pub(crate) const OPENBAO_AGENT_RESPONDER_SERVICE: &str = "openbao-agent-responder";
pub(crate) const DEFAULT_EAB_ENDPOINT_PATH: &str = "eab";
pub(crate) const DEFAULT_DB_USER: &str = "stepca";
pub(crate) const DEFAULT_DB_NAME: &str = "stepca";
pub(crate) const CA_CERTS_DIR: &str = "certs";
pub(crate) const CA_ROOT_CERT_FILENAME: &str = "root_ca.crt";
pub(crate) const CA_INTERMEDIATE_CERT_FILENAME: &str = "intermediate_ca.crt";
pub(crate) const CA_TRUST_KEY: &str = "trusted_ca_sha256";

pub(crate) mod openbao_constants {
pub(crate) const INIT_SECRET_SHARES: u8 = 3;
pub(crate) const INIT_SECRET_THRESHOLD: u8 = 2;
pub(crate) const TOKEN_TTL: &str = "1h";
pub(crate) const SECRET_ID_TTL: &str = "24h";

pub(crate) const POLICY_BOOTROOT_AGENT: &str = "bootroot-agent";
pub(crate) const POLICY_BOOTROOT_RESPONDER: &str = "bootroot-responder";
pub(crate) const POLICY_BOOTROOT_STEPCA: &str = "bootroot-stepca";

pub(crate) const APPROLE_BOOTROOT_AGENT: &str = "bootroot-agent-role";
pub(crate) const APPROLE_BOOTROOT_RESPONDER: &str = "bootroot-responder-role";
pub(crate) const APPROLE_BOOTROOT_STEPCA: &str = "bootroot-stepca-role";

pub(crate) const PATH_STEPCA_PASSWORD: &str = "bootroot/stepca/password";
pub(crate) const PATH_STEPCA_DB: &str = "bootroot/stepca/db";
pub(crate) const PATH_RESPONDER_HMAC: &str = "bootroot/responder/hmac";
pub(crate) const PATH_AGENT_EAB: &str = "bootroot/agent/eab";
pub(crate) const PATH_CA_TRUST: &str = "bootroot/ca";
}
15 changes: 15 additions & 0 deletions src/commands/init/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
mod constants;
mod paths;
mod steps;
mod types;

pub(crate) use constants::openbao_constants::{
INIT_SECRET_SHARES, INIT_SECRET_THRESHOLD, PATH_AGENT_EAB, PATH_CA_TRUST, PATH_RESPONDER_HMAC,
PATH_STEPCA_DB, PATH_STEPCA_PASSWORD, SECRET_ID_TTL, TOKEN_TTL,
};
pub(crate) use constants::{
DEFAULT_COMPOSE_FILE, DEFAULT_KV_MOUNT, DEFAULT_OPENBAO_URL, DEFAULT_SECRETS_DIR,
DEFAULT_STEPCA_PROVISIONER, DEFAULT_STEPCA_URL,
};
pub(crate) use steps::run_init;
pub(crate) use types::{DbCheckStatus, InitPlan, InitSummary, ResponderCheck, StepCaInitResult};
69 changes: 69 additions & 0 deletions src/commands/init/paths.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
use std::path::{Path, PathBuf};

use anyhow::{Context, Result};

use super::constants::DEFAULT_RESPONDER_ADMIN_URL;
use crate::cli::args::InitArgs;
use crate::i18n::Messages;

pub(crate) struct ResponderPaths {
pub(crate) template_path: PathBuf,
pub(crate) config_path: PathBuf,
}

pub(crate) struct StepCaTemplatePaths {
pub(crate) password_template_path: PathBuf,
pub(crate) ca_json_template_path: PathBuf,
}

pub(crate) struct OpenBaoAgentPaths {
pub(crate) stepca_agent_config: PathBuf,
pub(crate) responder_agent_config: PathBuf,
pub(crate) compose_override_path: Option<PathBuf>,
}

pub(crate) fn to_container_path(
secrets_dir: &Path,
path: &Path,
messages: &Messages,
) -> Result<String> {
let relative = path
.strip_prefix(secrets_dir)
.with_context(|| messages.error_resolve_path_failed(&path.display().to_string()))?;
Ok(format!("/openbao/secrets/{}", relative.to_string_lossy()))
}

pub(crate) fn compose_has_responder(compose_file: &Path, messages: &Messages) -> Result<bool> {
let compose_contents = std::fs::read_to_string(compose_file)
.with_context(|| messages.error_read_file_failed(&compose_file.display().to_string()))?;
Ok(compose_contents.contains("bootroot-http01"))
}

pub(crate) fn compose_has_openbao(compose_file: &Path, messages: &Messages) -> Result<bool> {
let compose_contents = std::fs::read_to_string(compose_file)
.with_context(|| messages.error_read_file_failed(&compose_file.display().to_string()))?;
Ok(compose_contents.contains("openbao"))
}

pub(crate) fn resolve_responder_url(
args: &InitArgs,
compose_has_responder: bool,
) -> Option<String> {
if let Some(responder_url) = args.responder_url.as_ref() {
return Some(responder_url.clone());
}
if compose_has_responder {
Some(DEFAULT_RESPONDER_ADMIN_URL.to_string())
} else {
None
}
}

pub(crate) fn resolve_openbao_agent_addr(openbao_url: &str, compose_has_openbao: bool) -> String {
if !compose_has_openbao {
return openbao_url.to_string();
}
openbao_url
.replace("localhost", "openbao")
.replace("127.0.0.1", "openbao")
}
Loading