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
21 changes: 9 additions & 12 deletions src/commands/rotate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ async fn rotate_eab(
)
.await
.with_context(|| messages.error_openbao_kv_write_failed())?;
sync_remote_eab_payloads(ctx, client, &credentials.kid, &credentials.hmac, messages).await?;
sync_service_eab_payloads(ctx, client, &credentials.kid, &credentials.hmac, messages).await?;

let updated = update_agent_configs(
ctx.state
Expand Down Expand Up @@ -372,7 +372,7 @@ async fn rotate_responder_hmac(
)
.await
.with_context(|| messages.error_openbao_kv_write_failed())?;
sync_remote_responder_hmac_payloads(ctx, client, &hmac, messages).await?;
sync_service_responder_hmac_payloads(ctx, client, &hmac, messages).await?;

let responder_path = ctx.paths.responder_config();
let config = if responder_path.exists() {
Expand Down Expand Up @@ -527,7 +527,7 @@ async fn write_remote_service_secret_id(
.with_context(|| messages.error_openbao_kv_write_failed())
}

async fn sync_remote_eab_payloads(
async fn sync_service_eab_payloads(
ctx: &RotateContext,
client: &OpenBaoClient,
kid: &str,
Expand All @@ -538,7 +538,6 @@ async fn sync_remote_eab_payloads(
.state
.services
.values()
.filter(|entry| matches!(entry.delivery_mode, DeliveryMode::RemoteBootstrap))
.map(|entry| entry.service_name.as_str())
{
client
Expand All @@ -553,7 +552,7 @@ async fn sync_remote_eab_payloads(
Ok(())
}

async fn sync_remote_responder_hmac_payloads(
async fn sync_service_responder_hmac_payloads(
ctx: &RotateContext,
client: &OpenBaoClient,
hmac: &str,
Expand All @@ -563,7 +562,6 @@ async fn sync_remote_responder_hmac_payloads(
.state
.services
.values()
.filter(|entry| matches!(entry.delivery_mode, DeliveryMode::RemoteBootstrap))
.map(|entry| entry.service_name.as_str())
{
client
Expand Down Expand Up @@ -1023,15 +1021,14 @@ async fn rotate_trust_sync(
.await
.with_context(|| messages.error_openbao_kv_write_failed())?;

// Sync trust to each remote service KV
let remote_services: Vec<String> = ctx
// Sync trust to each service KV
let service_names: Vec<String> = ctx
.state
.services
.values()
.filter(|entry| matches!(entry.delivery_mode, DeliveryMode::RemoteBootstrap))
.map(|entry| entry.service_name.clone())
.collect();
for service_name in &remote_services {
for service_name in &service_names {
client
.write_kv(
&ctx.kv_mount,
Expand Down Expand Up @@ -1068,10 +1065,10 @@ async fn rotate_trust_sync(
"{}",
messages.rotate_summary_trust_sync_global(&fingerprints.join(", "))
);
for service_name in &remote_services {
for service_name in &service_names {
println!(
"{}",
messages.rotate_summary_trust_sync_remote(service_name)
messages.rotate_summary_trust_sync_service(service_name)
);
}
Ok(())
Expand Down
113 changes: 56 additions & 57 deletions src/commands/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,8 +216,7 @@ async fn run_service_add_apply(
messages,
)
.await?;
sync_remote_service_bundle_if_needed(&client, state, resolved, &approle.secret_id, messages)
.await?;
sync_service_kv_bundle(&client, state, resolved, &approle.secret_id, messages).await?;

let applied = if matches!(resolved.delivery_mode, DeliveryMode::LocalFile) {
Some(
Expand Down Expand Up @@ -323,26 +322,34 @@ fn print_service_add_apply_summary(
);
}

async fn sync_remote_service_bundle_if_needed(
async fn sync_service_kv_bundle(
client: &OpenBaoClient,
state: &StateFile,
resolved: &ResolvedServiceAdd,
secret_id: &str,
messages: &Messages,
) -> Result<()> {
if !matches!(resolved.delivery_mode, DeliveryMode::RemoteBootstrap) {
return Ok(());
}
let material = read_remote_sync_material(client, &state.kv_mount, messages).await?;
write_remote_service_sync_bundle(
let material = read_service_sync_material(client, &state.kv_mount, messages).await?;
write_service_kv_secrets(
client,
&state.kv_mount,
&resolved.service_name,
secret_id,
&material,
messages,
)
.await
.await?;
if matches!(resolved.delivery_mode, DeliveryMode::RemoteBootstrap) {
let base = format!("{SERVICE_KV_BASE}/{}", resolved.service_name);
client
.write_kv(
&state.kv_mount,
&format!("{base}/secret_id"),
serde_json::json!({ SERVICE_SECRET_ID_KEY: secret_id }),
)
.await
.with_context(|| messages.error_openbao_kv_write_failed())?;
}
Ok(())
}

async fn run_service_add_remote_idempotent(
Expand Down Expand Up @@ -501,9 +508,9 @@ struct RemoteBootstrapArtifact {
profile_key_path: String,
}

struct RemoteSyncMaterial {
eab_kid: String,
eab_hmac: String,
struct ServiceSyncMaterial {
eab_kid: Option<String>,
eab_hmac: Option<String>,
responder_hmac: String,
trusted_ca_sha256: Vec<String>,
ca_bundle_pem: Option<String>,
Expand Down Expand Up @@ -1071,20 +1078,12 @@ fn read_required_string(
.ok_or_else(|| anyhow::anyhow!(missing_message.to_string()))
}

async fn read_remote_sync_material(
async fn read_service_sync_material(
client: &OpenBaoClient,
kv_mount: &str,
messages: &Messages,
) -> Result<RemoteSyncMaterial> {
let eab = client
.read_kv(kv_mount, PATH_AGENT_EAB)
.await
.with_context(|| {
format!(
"{} ({PATH_AGENT_EAB})",
messages.error_openbao_kv_read_failed()
)
})?;
) -> Result<ServiceSyncMaterial> {
let eab = client.read_kv(kv_mount, PATH_AGENT_EAB).await.ok();
let responder_hmac = client
.read_kv(kv_mount, PATH_RESPONDER_HMAC)
.await
Expand Down Expand Up @@ -1112,17 +1111,24 @@ async fn read_remote_sync_material(
if trusted_ca_sha256.is_empty() {
anyhow::bail!(messages.error_ca_trust_empty());
}
Ok(RemoteSyncMaterial {
eab_kid: read_required_string(
&eab,
SERVICE_EAB_KID_KEY,
"OpenBao EAB data missing key: kid",
)?,
eab_hmac: read_required_string(
&eab,
SERVICE_EAB_HMAC_KEY,
"OpenBao EAB data missing key: hmac",
)?,
let (eab_kid, eab_hmac) = match &eab {
Some(data) => (
Some(read_required_string(
data,
SERVICE_EAB_KID_KEY,
"OpenBao EAB data missing key: kid",
)?),
Some(read_required_string(
data,
SERVICE_EAB_HMAC_KEY,
"OpenBao EAB data missing key: hmac",
)?),
),
None => (None, None),
};
Ok(ServiceSyncMaterial {
eab_kid,
eab_hmac,
responder_hmac: read_required_string(
&responder_hmac,
"value",
Expand All @@ -1136,34 +1142,27 @@ async fn read_remote_sync_material(
})
}

async fn write_remote_service_sync_bundle(
async fn write_service_kv_secrets(
client: &OpenBaoClient,
kv_mount: &str,
service_name: &str,
secret_id: &str,
material: &RemoteSyncMaterial,
material: &ServiceSyncMaterial,
messages: &Messages,
) -> Result<()> {
let base = format!("{SERVICE_KV_BASE}/{service_name}");
client
.write_kv(
kv_mount,
&format!("{base}/secret_id"),
serde_json::json!({ SERVICE_SECRET_ID_KEY: secret_id }),
)
.await
.with_context(|| messages.error_openbao_kv_write_failed())?;
client
.write_kv(
kv_mount,
&format!("{base}/eab"),
serde_json::json!({
SERVICE_EAB_KID_KEY: &material.eab_kid,
SERVICE_EAB_HMAC_KEY: &material.eab_hmac,
}),
)
.await
.with_context(|| messages.error_openbao_kv_write_failed())?;
if let (Some(kid), Some(hmac)) = (&material.eab_kid, &material.eab_hmac) {
client
.write_kv(
kv_mount,
&format!("{base}/eab"),
serde_json::json!({
SERVICE_EAB_KID_KEY: kid,
SERVICE_EAB_HMAC_KEY: hmac,
}),
)
.await
.with_context(|| messages.error_openbao_kv_write_failed())?;
}
client
.write_kv(
kv_mount,
Expand Down
2 changes: 1 addition & 1 deletion src/i18n/en.rs
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ pub(super) static STRINGS: Strings = Strings {
prompt_rotate_trust_sync: "Sync CA trust data to OpenBao and update services? [y/N]",
prompt_rotate_force_reissue: "Delete certificates for {service_name} and trigger reissuance? [y/N]",
rotate_summary_trust_sync_global: "- CA trust updated: {value}",
rotate_summary_trust_sync_remote: "- remote service trust synced: {value}",
rotate_summary_trust_sync_service: "- service trust synced: {value}",
rotate_summary_force_reissue_deleted: "- {service_name}: cert/key deleted ({cert_path}, {key_path})",
rotate_summary_force_reissue_local_signal: "- {service_name}: signaled bootroot-agent for renewal",
rotate_summary_force_reissue_remote_hint: "- {service_name}: run `bootroot-remote bootstrap` on the service host to reissue",
Expand Down
2 changes: 1 addition & 1 deletion src/i18n/ko.rs
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ pub(super) static STRINGS: Strings = Strings {
prompt_rotate_trust_sync: "CA trust 데이터를 OpenBao에 동기화하고 서비스를 갱신할까요? [y/N]",
prompt_rotate_force_reissue: "{service_name} 인증서를 삭제하고 재발급을 시작할까요? [y/N]",
rotate_summary_trust_sync_global: "- CA trust 갱신: {value}",
rotate_summary_trust_sync_remote: "- 원격 서비스 trust 동기화: {value}",
rotate_summary_trust_sync_service: "- 서비스 trust 동기화: {value}",
rotate_summary_force_reissue_deleted: "- {service_name}: cert/key 삭제 ({cert_path}, {key_path})",
rotate_summary_force_reissue_local_signal: "- {service_name}: 인증서 갱신을 위해 bootroot-agent에 시그널 전송",
rotate_summary_force_reissue_remote_hint: "- {service_name}: 서비스 머신에서 `bootroot-remote bootstrap`을 실행하여 재발급하세요",
Expand Down
6 changes: 3 additions & 3 deletions src/i18n/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ pub(crate) struct Strings {
pub(crate) prompt_rotate_trust_sync: &'static str,
pub(crate) prompt_rotate_force_reissue: &'static str,
pub(crate) rotate_summary_trust_sync_global: &'static str,
pub(crate) rotate_summary_trust_sync_remote: &'static str,
pub(crate) rotate_summary_trust_sync_service: &'static str,
pub(crate) rotate_summary_force_reissue_deleted: &'static str,
pub(crate) rotate_summary_force_reissue_local_signal: &'static str,
pub(crate) rotate_summary_force_reissue_remote_hint: &'static str,
Expand Down Expand Up @@ -1780,9 +1780,9 @@ impl Messages {
)
}

pub(crate) fn rotate_summary_trust_sync_remote(&self, value: &str) -> String {
pub(crate) fn rotate_summary_trust_sync_service(&self, value: &str) -> String {
format_template(
self.strings().rotate_summary_trust_sync_remote,
self.strings().rotate_summary_trust_sync_service,
&[("value", value)],
)
}
Expand Down
9 changes: 9 additions & 0 deletions tests/bootroot_rotate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -748,6 +748,15 @@ async fn stub_openbao_for_eab_rotation(server: &MockServer) {
.respond_with(ResponseTemplate::new(200).set_body_json(json!({})))
.mount(server)
.await;

Mock::given(method("POST"))
.and(path(format!(
"/v1/secret/data/bootroot/services/{SECONDARY_SERVICE_NAME}/eab"
)))
.and(header("X-Vault-Token", support::ROOT_TOKEN))
.respond_with(ResponseTemplate::new(200).set_body_json(json!({})))
.mount(server)
.await;
}

async fn stub_openbao_for_responder_hmac_rotation(server: &MockServer, hmac: &str) {
Expand Down
Loading